Commit | Line | Data |
---|---|---|
1394f032 | 1 | /* |
96f1050d | 2 | * GPIO Abstraction Layer |
1394f032 | 3 | * |
05bbec38 | 4 | * Copyright 2006-2010 Analog Devices Inc. |
1394f032 | 5 | * |
96f1050d | 6 | * Licensed under the GPL-2 or later |
1394f032 BW |
7 | */ |
8 | ||
168f1212 | 9 | #include <linux/delay.h> |
1394f032 BW |
10 | #include <linux/module.h> |
11 | #include <linux/err.h> | |
1545a111 | 12 | #include <linux/proc_fs.h> |
6362ec27 | 13 | #include <linux/seq_file.h> |
03be35d1 LW |
14 | #include <linux/gpio/driver.h> |
15 | /* FIXME: consumer API required for gpio_set_value() etc, get rid of this */ | |
54e4ff4d | 16 | #include <linux/gpio.h> |
1394f032 BW |
17 | #include <linux/irq.h> |
18 | ||
2b39331a MH |
19 | #if ANOMALY_05000311 || ANOMALY_05000323 |
20 | enum { | |
21 | AWA_data = SYSCR, | |
22 | AWA_data_clear = SYSCR, | |
23 | AWA_data_set = SYSCR, | |
24 | AWA_toggle = SYSCR, | |
6ed83942 GY |
25 | AWA_maska = BFIN_UART_SCR, |
26 | AWA_maska_clear = BFIN_UART_SCR, | |
27 | AWA_maska_set = BFIN_UART_SCR, | |
28 | AWA_maska_toggle = BFIN_UART_SCR, | |
29 | AWA_maskb = BFIN_UART_GCTL, | |
30 | AWA_maskb_clear = BFIN_UART_GCTL, | |
31 | AWA_maskb_set = BFIN_UART_GCTL, | |
32 | AWA_maskb_toggle = BFIN_UART_GCTL, | |
2b39331a MH |
33 | AWA_dir = SPORT1_STAT, |
34 | AWA_polar = SPORT1_STAT, | |
35 | AWA_edge = SPORT1_STAT, | |
36 | AWA_both = SPORT1_STAT, | |
37 | #if ANOMALY_05000311 | |
38 | AWA_inen = TIMER_ENABLE, | |
39 | #elif ANOMALY_05000323 | |
40 | AWA_inen = DMA1_1_CONFIG, | |
41 | #endif | |
42 | }; | |
43 | /* Anomaly Workaround */ | |
44 | #define AWA_DUMMY_READ(name) bfin_read16(AWA_ ## name) | |
45 | #else | |
46 | #define AWA_DUMMY_READ(...) do { } while (0) | |
47 | #endif | |
48 | ||
f556309e | 49 | static struct gpio_port_t * const gpio_array[] = { |
dc26aec2 | 50 | #if defined(BF533_FAMILY) || defined(BF538_FAMILY) |
1394f032 | 51 | (struct gpio_port_t *) FIO_FLAG_D, |
269647dc | 52 | #elif defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) |
1394f032 BW |
53 | (struct gpio_port_t *) PORTFIO, |
54 | (struct gpio_port_t *) PORTGIO, | |
55 | (struct gpio_port_t *) PORTHIO, | |
f556309e MF |
56 | #elif defined(BF561_FAMILY) |
57 | (struct gpio_port_t *) FIO0_FLAG_D, | |
58 | (struct gpio_port_t *) FIO1_FLAG_D, | |
59 | (struct gpio_port_t *) FIO2_FLAG_D, | |
f556309e MF |
60 | #else |
61 | # error no gpio arrays defined | |
62 | #endif | |
1394f032 BW |
63 | }; |
64 | ||
269647dc | 65 | #if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) |
f556309e | 66 | static unsigned short * const port_fer[] = { |
1394f032 BW |
67 | (unsigned short *) PORTF_FER, |
68 | (unsigned short *) PORTG_FER, | |
69 | (unsigned short *) PORTH_FER, | |
70 | }; | |
1394f032 | 71 | |
f556309e MF |
72 | # if !defined(BF537_FAMILY) |
73 | static unsigned short * const port_mux[] = { | |
59003145 MH |
74 | (unsigned short *) PORTF_MUX, |
75 | (unsigned short *) PORTG_MUX, | |
76 | (unsigned short *) PORTH_MUX, | |
77 | }; | |
78 | ||
79 | static const | |
0ce5eaf8 | 80 | u8 pmux_offset[][16] = { |
269647dc | 81 | # if defined(CONFIG_BF52x) |
0ce5eaf8 GY |
82 | { 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 4, 6, 8, 8, 10, 10 }, /* PORTF */ |
83 | { 0, 0, 0, 0, 0, 2, 2, 4, 4, 6, 8, 10, 10, 10, 12, 12 }, /* PORTG */ | |
84 | { 0, 0, 0, 0, 0, 0, 0, 0, 2, 4, 4, 4, 4, 4, 4, 4 }, /* PORTH */ | |
269647dc | 85 | # elif defined(CONFIG_BF51x) |
0ce5eaf8 GY |
86 | { 0, 2, 2, 2, 2, 2, 2, 4, 6, 6, 6, 8, 8, 8, 8, 10 }, /* PORTF */ |
87 | { 0, 0, 0, 2, 4, 6, 6, 6, 8, 10, 10, 12, 14, 14, 14, 14 }, /* PORTG */ | |
88 | { 0, 0, 0, 0, 2, 2, 4, 6, 10, 10, 10, 10, 10, 10, 10, 10 }, /* PORTH */ | |
89 | # endif | |
90 | }; | |
f556309e | 91 | # endif |
0ce5eaf8 | 92 | |
621dd247 MH |
93 | #elif defined(BF538_FAMILY) |
94 | static unsigned short * const port_fer[] = { | |
95 | (unsigned short *) PORTCIO_FER, | |
96 | (unsigned short *) PORTDIO_FER, | |
97 | (unsigned short *) PORTEIO_FER, | |
98 | }; | |
d2b11a46 MH |
99 | #endif |
100 | ||
812ae98f | 101 | #define RESOURCE_LABEL_SIZE 16 |
8c613623 | 102 | |
fac3cf43 | 103 | static struct str_ident { |
8c613623 | 104 | char name[RESOURCE_LABEL_SIZE]; |
fac3cf43 | 105 | } str_ident[MAX_RESOURCES]; |
1394f032 | 106 | |
1efc80b5 | 107 | #if defined(CONFIG_PM) |
397861cd | 108 | static struct gpio_port_s gpio_bank_saved[GPIO_BANK_NUM]; |
9466a051 MF |
109 | # ifdef BF538_FAMILY |
110 | static unsigned short port_fer_saved[3]; | |
111 | # endif | |
59003145 MH |
112 | #endif |
113 | ||
74c04503 | 114 | static void gpio_error(unsigned gpio) |
acbcd263 MH |
115 | { |
116 | printk(KERN_ERR "bfin-gpio: GPIO %d wasn't requested!\n", gpio); | |
117 | } | |
118 | ||
c58c2140 MH |
119 | static void set_label(unsigned short ident, const char *label) |
120 | { | |
e9fae189 | 121 | if (label) { |
8c613623 | 122 | strncpy(str_ident[ident].name, label, |
c58c2140 | 123 | RESOURCE_LABEL_SIZE); |
8c613623 | 124 | str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0; |
c58c2140 MH |
125 | } |
126 | } | |
127 | ||
128 | static char *get_label(unsigned short ident) | |
129 | { | |
8c613623 | 130 | return (*str_ident[ident].name ? str_ident[ident].name : "UNKNOWN"); |
c58c2140 MH |
131 | } |
132 | ||
133 | static int cmp_label(unsigned short ident, const char *label) | |
134 | { | |
fac3cf43 MH |
135 | if (label == NULL) { |
136 | dump_stack(); | |
137 | printk(KERN_ERR "Please provide none-null label\n"); | |
138 | } | |
139 | ||
e9fae189 | 140 | if (label) |
1f7d373f | 141 | return strcmp(str_ident[ident].name, label); |
c58c2140 MH |
142 | else |
143 | return -EINVAL; | |
144 | } | |
145 | ||
332824b8 MF |
146 | #define map_entry(m, i) reserved_##m##_map[gpio_bank(i)] |
147 | #define is_reserved(m, i, e) (map_entry(m, i) & gpio_bit(i)) | |
148 | #define reserve(m, i) (map_entry(m, i) |= gpio_bit(i)) | |
149 | #define unreserve(m, i) (map_entry(m, i) &= ~gpio_bit(i)) | |
150 | #define DECLARE_RESERVED_MAP(m, c) static unsigned short reserved_##m##_map[c] | |
151 | ||
152 | DECLARE_RESERVED_MAP(gpio, GPIO_BANK_NUM); | |
382dbe5b | 153 | DECLARE_RESERVED_MAP(peri, DIV_ROUND_UP(MAX_RESOURCES, GPIO_BANKSIZE)); |
332824b8 MF |
154 | DECLARE_RESERVED_MAP(gpio_irq, GPIO_BANK_NUM); |
155 | ||
156 | inline int check_gpio(unsigned gpio) | |
157 | { | |
332824b8 MF |
158 | if (gpio >= MAX_BLACKFIN_GPIOS) |
159 | return -EINVAL; | |
160 | return 0; | |
161 | } | |
162 | ||
a2c8cfef | 163 | static void port_setup(unsigned gpio, unsigned short usage) |
1394f032 | 164 | { |
621dd247 MH |
165 | #if defined(BF538_FAMILY) |
166 | /* | |
167 | * BF538/9 Port C,D and E are special. | |
168 | * Inverted PORT_FER polarity on CDE and no PORF_FER on F | |
169 | * Regular PORT F GPIOs are handled here, CDE are exclusively | |
170 | * managed by GPIOLIB | |
171 | */ | |
172 | ||
173 | if (gpio < MAX_BLACKFIN_GPIOS || gpio >= MAX_RESOURCES) | |
174 | return; | |
175 | ||
176 | gpio -= MAX_BLACKFIN_GPIOS; | |
177 | ||
178 | if (usage == GPIO_USAGE) | |
179 | *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio); | |
180 | else | |
181 | *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio); | |
182 | SSYNC(); | |
183 | return; | |
184 | #endif | |
185 | ||
a2d03a1d MF |
186 | if (check_gpio(gpio)) |
187 | return; | |
188 | ||
269647dc | 189 | #if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) |
a2d03a1d MF |
190 | if (usage == GPIO_USAGE) |
191 | *port_fer[gpio_bank(gpio)] &= ~gpio_bit(gpio); | |
192 | else | |
193 | *port_fer[gpio_bank(gpio)] |= gpio_bit(gpio); | |
194 | SSYNC(); | |
1394f032 | 195 | #endif |
a2d03a1d | 196 | } |
1394f032 | 197 | |
c58c2140 | 198 | #ifdef BF537_FAMILY |
05bbec38 | 199 | static const s8 port_mux[] = { |
200 | [GPIO_PF0] = 3, | |
201 | [GPIO_PF1] = 3, | |
202 | [GPIO_PF2] = 4, | |
203 | [GPIO_PF3] = 4, | |
204 | [GPIO_PF4] = 5, | |
205 | [GPIO_PF5] = 6, | |
206 | [GPIO_PF6] = 7, | |
207 | [GPIO_PF7] = 8, | |
208 | [GPIO_PF8 ... GPIO_PF15] = -1, | |
209 | [GPIO_PG0 ... GPIO_PG7] = -1, | |
210 | [GPIO_PG8] = 9, | |
211 | [GPIO_PG9] = 9, | |
212 | [GPIO_PG10] = 10, | |
213 | [GPIO_PG11] = 10, | |
214 | [GPIO_PG12] = 10, | |
215 | [GPIO_PG13] = 11, | |
216 | [GPIO_PG14] = 11, | |
217 | [GPIO_PG15] = 11, | |
218 | [GPIO_PH0 ... GPIO_PH15] = -1, | |
219 | [PORT_PJ0 ... PORT_PJ3] = -1, | |
220 | [PORT_PJ4] = 1, | |
221 | [PORT_PJ5] = 1, | |
222 | [PORT_PJ6 ... PORT_PJ9] = -1, | |
223 | [PORT_PJ10] = 0, | |
224 | [PORT_PJ11] = 0, | |
c58c2140 MH |
225 | }; |
226 | ||
05bbec38 | 227 | static int portmux_group_check(unsigned short per) |
c58c2140 | 228 | { |
05bbec38 | 229 | u16 ident = P_IDENT(per); |
f556309e | 230 | u16 function = P_FUNCT2MUX(per); |
05bbec38 | 231 | s8 offset = port_mux[ident]; |
f70de486 | 232 | u16 m, pmux, pfunc, mask; |
c58c2140 | 233 | |
05bbec38 | 234 | if (offset < 0) |
235 | return 0; | |
c58c2140 | 236 | |
05bbec38 | 237 | pmux = bfin_read_PORT_MUX(); |
238 | for (m = 0; m < ARRAY_SIZE(port_mux); ++m) { | |
239 | if (m == ident) | |
240 | continue; | |
241 | if (port_mux[m] != offset) | |
242 | continue; | |
243 | if (!is_reserved(peri, m, 1)) | |
244 | continue; | |
245 | ||
246 | if (offset == 1) | |
f70de486 | 247 | mask = 3; |
05bbec38 | 248 | else |
f70de486 SZ |
249 | mask = 1; |
250 | ||
251 | pfunc = (pmux >> offset) & mask; | |
252 | if (pfunc != (function & mask)) { | |
05bbec38 | 253 | pr_err("pin group conflict! request pin %d func %d conflict with pin %d func %d\n", |
254 | ident, function, m, pfunc); | |
255 | return -EINVAL; | |
256 | } | |
257 | } | |
c58c2140 | 258 | |
05bbec38 | 259 | return 0; |
260 | } | |
261 | ||
262 | static void portmux_setup(unsigned short per) | |
263 | { | |
264 | u16 ident = P_IDENT(per); | |
265 | u16 function = P_FUNCT2MUX(per); | |
266 | s8 offset = port_mux[ident]; | |
f70de486 | 267 | u16 pmux, mask; |
c58c2140 | 268 | |
05bbec38 | 269 | if (offset == -1) |
270 | return; | |
c58c2140 | 271 | |
05bbec38 | 272 | pmux = bfin_read_PORT_MUX(); |
f70de486 SZ |
273 | if (offset == 1) |
274 | mask = 3; | |
05bbec38 | 275 | else |
f70de486 SZ |
276 | mask = 1; |
277 | ||
278 | pmux &= ~(mask << offset); | |
279 | pmux |= ((function & mask) << offset); | |
280 | ||
05bbec38 | 281 | bfin_write_PORT_MUX(pmux); |
c58c2140 | 282 | } |
269647dc | 283 | #elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) |
05bbec38 | 284 | static int portmux_group_check(unsigned short per) |
285 | { | |
286 | u16 ident = P_IDENT(per); | |
287 | u16 function = P_FUNCT2MUX(per); | |
288 | u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)]; | |
289 | u16 pin, gpiopin, pfunc; | |
290 | ||
291 | for (pin = 0; pin < GPIO_BANKSIZE; ++pin) { | |
292 | if (offset != pmux_offset[gpio_bank(ident)][pin]) | |
293 | continue; | |
294 | ||
295 | gpiopin = gpio_bank(ident) * GPIO_BANKSIZE + pin; | |
296 | if (gpiopin == ident) | |
297 | continue; | |
298 | if (!is_reserved(peri, gpiopin, 1)) | |
299 | continue; | |
300 | ||
301 | pfunc = *port_mux[gpio_bank(ident)]; | |
302 | pfunc = (pfunc >> offset) & 3; | |
303 | if (pfunc != function) { | |
304 | pr_err("pin group conflict! request pin %d func %d conflict with pin %d func %d\n", | |
305 | ident, function, gpiopin, pfunc); | |
306 | return -EINVAL; | |
307 | } | |
308 | } | |
309 | ||
310 | return 0; | |
311 | } | |
312 | ||
f556309e | 313 | inline void portmux_setup(unsigned short per) |
59003145 | 314 | { |
05bbec38 | 315 | u16 ident = P_IDENT(per); |
316 | u16 function = P_FUNCT2MUX(per); | |
59003145 | 317 | u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)]; |
05bbec38 | 318 | u16 pmux; |
59003145 MH |
319 | |
320 | pmux = *port_mux[gpio_bank(ident)]; | |
05bbec38 | 321 | if (((pmux >> offset) & 3) == function) |
322 | return; | |
59003145 MH |
323 | pmux &= ~(3 << offset); |
324 | pmux |= (function & 3) << offset; | |
325 | *port_mux[gpio_bank(ident)] = pmux; | |
326 | SSYNC(); | |
327 | } | |
c58c2140 MH |
328 | #else |
329 | # define portmux_setup(...) do { } while (0) | |
05bbec38 | 330 | static int portmux_group_check(unsigned short per) |
331 | { | |
332 | return 0; | |
333 | } | |
c58c2140 | 334 | #endif |
1394f032 | 335 | |
1394f032 BW |
336 | /*********************************************************** |
337 | * | |
338 | * FUNCTIONS: Blackfin General Purpose Ports Access Functions | |
339 | * | |
340 | * INPUTS/OUTPUTS: | |
341 | * gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS | |
342 | * | |
343 | * | |
344 | * DESCRIPTION: These functions abstract direct register access | |
345 | * to Blackfin processor General Purpose | |
346 | * Ports Regsiters | |
347 | * | |
348 | * CAUTION: These functions do not belong to the GPIO Driver API | |
349 | ************************************************************* | |
350 | * MODIFICATION HISTORY : | |
351 | **************************************************************/ | |
352 | ||
353 | /* Set a specific bit */ | |
354 | ||
355 | #define SET_GPIO(name) \ | |
a2c8cfef | 356 | void set_gpio_ ## name(unsigned gpio, unsigned short arg) \ |
1394f032 BW |
357 | { \ |
358 | unsigned long flags; \ | |
3b139cdb | 359 | flags = hard_local_irq_save(); \ |
1394f032 | 360 | if (arg) \ |
f556309e | 361 | gpio_array[gpio_bank(gpio)]->name |= gpio_bit(gpio); \ |
1394f032 | 362 | else \ |
f556309e | 363 | gpio_array[gpio_bank(gpio)]->name &= ~gpio_bit(gpio); \ |
2b39331a | 364 | AWA_DUMMY_READ(name); \ |
3b139cdb | 365 | hard_local_irq_restore(flags); \ |
1394f032 BW |
366 | } \ |
367 | EXPORT_SYMBOL(set_gpio_ ## name); | |
368 | ||
f556309e MF |
369 | SET_GPIO(dir) /* set_gpio_dir() */ |
370 | SET_GPIO(inen) /* set_gpio_inen() */ | |
371 | SET_GPIO(polar) /* set_gpio_polar() */ | |
372 | SET_GPIO(edge) /* set_gpio_edge() */ | |
373 | SET_GPIO(both) /* set_gpio_both() */ | |
1394f032 BW |
374 | |
375 | ||
2b39331a | 376 | #define SET_GPIO_SC(name) \ |
a2c8cfef | 377 | void set_gpio_ ## name(unsigned gpio, unsigned short arg) \ |
2b39331a MH |
378 | { \ |
379 | unsigned long flags; \ | |
f556309e | 380 | if (ANOMALY_05000311 || ANOMALY_05000323) \ |
3b139cdb | 381 | flags = hard_local_irq_save(); \ |
1394f032 | 382 | if (arg) \ |
f556309e | 383 | gpio_array[gpio_bank(gpio)]->name ## _set = gpio_bit(gpio); \ |
1394f032 | 384 | else \ |
f556309e MF |
385 | gpio_array[gpio_bank(gpio)]->name ## _clear = gpio_bit(gpio); \ |
386 | if (ANOMALY_05000311 || ANOMALY_05000323) { \ | |
387 | AWA_DUMMY_READ(name); \ | |
3b139cdb | 388 | hard_local_irq_restore(flags); \ |
f556309e | 389 | } \ |
1394f032 BW |
390 | } \ |
391 | EXPORT_SYMBOL(set_gpio_ ## name); | |
392 | ||
393 | SET_GPIO_SC(maska) | |
394 | SET_GPIO_SC(maskb) | |
1394f032 | 395 | SET_GPIO_SC(data) |
1394f032 | 396 | |
a2c8cfef | 397 | void set_gpio_toggle(unsigned gpio) |
1394f032 BW |
398 | { |
399 | unsigned long flags; | |
f556309e | 400 | if (ANOMALY_05000311 || ANOMALY_05000323) |
3b139cdb | 401 | flags = hard_local_irq_save(); |
f556309e MF |
402 | gpio_array[gpio_bank(gpio)]->toggle = gpio_bit(gpio); |
403 | if (ANOMALY_05000311 || ANOMALY_05000323) { | |
404 | AWA_DUMMY_READ(toggle); | |
3b139cdb | 405 | hard_local_irq_restore(flags); |
f556309e | 406 | } |
1394f032 | 407 | } |
1394f032 BW |
408 | EXPORT_SYMBOL(set_gpio_toggle); |
409 | ||
410 | ||
411 | /*Set current PORT date (16-bit word)*/ | |
412 | ||
413 | #define SET_GPIO_P(name) \ | |
a2c8cfef | 414 | void set_gpiop_ ## name(unsigned gpio, unsigned short arg) \ |
1394f032 | 415 | { \ |
2b39331a | 416 | unsigned long flags; \ |
f556309e | 417 | if (ANOMALY_05000311 || ANOMALY_05000323) \ |
3b139cdb | 418 | flags = hard_local_irq_save(); \ |
f556309e MF |
419 | gpio_array[gpio_bank(gpio)]->name = arg; \ |
420 | if (ANOMALY_05000311 || ANOMALY_05000323) { \ | |
421 | AWA_DUMMY_READ(name); \ | |
3b139cdb | 422 | hard_local_irq_restore(flags); \ |
f556309e | 423 | } \ |
2b39331a MH |
424 | } \ |
425 | EXPORT_SYMBOL(set_gpiop_ ## name); | |
1394f032 | 426 | |
2b39331a | 427 | SET_GPIO_P(data) |
1394f032 BW |
428 | SET_GPIO_P(dir) |
429 | SET_GPIO_P(inen) | |
430 | SET_GPIO_P(polar) | |
431 | SET_GPIO_P(edge) | |
432 | SET_GPIO_P(both) | |
433 | SET_GPIO_P(maska) | |
434 | SET_GPIO_P(maskb) | |
435 | ||
1394f032 | 436 | /* Get a specific bit */ |
2b39331a | 437 | #define GET_GPIO(name) \ |
a2c8cfef | 438 | unsigned short get_gpio_ ## name(unsigned gpio) \ |
2b39331a MH |
439 | { \ |
440 | unsigned long flags; \ | |
441 | unsigned short ret; \ | |
f556309e | 442 | if (ANOMALY_05000311 || ANOMALY_05000323) \ |
3b139cdb | 443 | flags = hard_local_irq_save(); \ |
f556309e MF |
444 | ret = 0x01 & (gpio_array[gpio_bank(gpio)]->name >> gpio_sub_n(gpio)); \ |
445 | if (ANOMALY_05000311 || ANOMALY_05000323) { \ | |
446 | AWA_DUMMY_READ(name); \ | |
3b139cdb | 447 | hard_local_irq_restore(flags); \ |
f556309e | 448 | } \ |
2b39331a MH |
449 | return ret; \ |
450 | } \ | |
451 | EXPORT_SYMBOL(get_gpio_ ## name); | |
1394f032 | 452 | |
2b39331a | 453 | GET_GPIO(data) |
1394f032 BW |
454 | GET_GPIO(dir) |
455 | GET_GPIO(inen) | |
456 | GET_GPIO(polar) | |
457 | GET_GPIO(edge) | |
458 | GET_GPIO(both) | |
459 | GET_GPIO(maska) | |
460 | GET_GPIO(maskb) | |
461 | ||
1394f032 BW |
462 | /*Get current PORT date (16-bit word)*/ |
463 | ||
2b39331a | 464 | #define GET_GPIO_P(name) \ |
a2c8cfef | 465 | unsigned short get_gpiop_ ## name(unsigned gpio) \ |
2b39331a MH |
466 | { \ |
467 | unsigned long flags; \ | |
468 | unsigned short ret; \ | |
f556309e | 469 | if (ANOMALY_05000311 || ANOMALY_05000323) \ |
3b139cdb | 470 | flags = hard_local_irq_save(); \ |
f556309e MF |
471 | ret = (gpio_array[gpio_bank(gpio)]->name); \ |
472 | if (ANOMALY_05000311 || ANOMALY_05000323) { \ | |
473 | AWA_DUMMY_READ(name); \ | |
3b139cdb | 474 | hard_local_irq_restore(flags); \ |
f556309e | 475 | } \ |
2b39331a MH |
476 | return ret; \ |
477 | } \ | |
478 | EXPORT_SYMBOL(get_gpiop_ ## name); | |
1394f032 | 479 | |
2b39331a | 480 | GET_GPIO_P(data) |
1394f032 BW |
481 | GET_GPIO_P(dir) |
482 | GET_GPIO_P(inen) | |
483 | GET_GPIO_P(polar) | |
484 | GET_GPIO_P(edge) | |
485 | GET_GPIO_P(both) | |
486 | GET_GPIO_P(maska) | |
487 | GET_GPIO_P(maskb) | |
488 | ||
1394f032 BW |
489 | |
490 | #ifdef CONFIG_PM | |
332824b8 | 491 | DECLARE_RESERVED_MAP(wakeup, GPIO_BANK_NUM); |
f556309e MF |
492 | |
493 | static const unsigned int sic_iwr_irqs[] = { | |
494 | #if defined(BF533_FAMILY) | |
495 | IRQ_PROG_INTB | |
496 | #elif defined(BF537_FAMILY) | |
8c054103 | 497 | IRQ_PF_INTB_WATCH, IRQ_PORTG_INTB, IRQ_PH_INTB_MAC_TX |
f556309e MF |
498 | #elif defined(BF538_FAMILY) |
499 | IRQ_PORTF_INTB | |
269647dc | 500 | #elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) |
f556309e MF |
501 | IRQ_PORTF_INTB, IRQ_PORTG_INTB, IRQ_PORTH_INTB |
502 | #elif defined(BF561_FAMILY) | |
503 | IRQ_PROG0_INTB, IRQ_PROG1_INTB, IRQ_PROG2_INTB | |
504 | #else | |
505 | # error no SIC_IWR defined | |
506 | #endif | |
507 | }; | |
508 | ||
1394f032 BW |
509 | /*********************************************************** |
510 | * | |
511 | * FUNCTIONS: Blackfin PM Setup API | |
512 | * | |
513 | * INPUTS/OUTPUTS: | |
514 | * gpio - GPIO Number between 0 and MAX_BLACKFIN_GPIOS | |
515 | * type - | |
516 | * PM_WAKE_RISING | |
517 | * PM_WAKE_FALLING | |
518 | * PM_WAKE_HIGH | |
519 | * PM_WAKE_LOW | |
520 | * PM_WAKE_BOTH_EDGES | |
521 | * | |
522 | * DESCRIPTION: Blackfin PM Driver API | |
523 | * | |
524 | * CAUTION: | |
525 | ************************************************************* | |
526 | * MODIFICATION HISTORY : | |
527 | **************************************************************/ | |
54e4ff4d | 528 | int bfin_gpio_pm_wakeup_ctrl(unsigned gpio, unsigned ctrl) |
1394f032 BW |
529 | { |
530 | unsigned long flags; | |
531 | ||
532 | if (check_gpio(gpio) < 0) | |
bb84dbf6 | 533 | return -EINVAL; |
1394f032 | 534 | |
3b139cdb | 535 | flags = hard_local_irq_save(); |
bb84dbf6 | 536 | if (ctrl) |
332824b8 | 537 | reserve(wakeup, gpio); |
1394f032 | 538 | else |
332824b8 | 539 | unreserve(wakeup, gpio); |
1394f032 | 540 | |
bb84dbf6 | 541 | set_gpio_maskb(gpio, ctrl); |
3b139cdb | 542 | hard_local_irq_restore(flags); |
2b39331a | 543 | |
cfefe3c6 | 544 | return 0; |
1394f032 BW |
545 | } |
546 | ||
54e4ff4d | 547 | int bfin_gpio_pm_standby_ctrl(unsigned ctrl) |
1394f032 BW |
548 | { |
549 | u16 bank, mask, i; | |
550 | ||
1f83b8f1 | 551 | for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { |
332824b8 | 552 | mask = map_entry(wakeup, i); |
1394f032 BW |
553 | bank = gpio_bank(i); |
554 | ||
bb84dbf6 MH |
555 | if (mask) |
556 | bfin_internal_set_wake(sic_iwr_irqs[bank], ctrl); | |
1394f032 | 557 | } |
bb84dbf6 | 558 | return 0; |
1394f032 BW |
559 | } |
560 | ||
1efc80b5 MH |
561 | void bfin_gpio_pm_hibernate_suspend(void) |
562 | { | |
563 | int i, bank; | |
564 | ||
9466a051 MF |
565 | #ifdef BF538_FAMILY |
566 | for (i = 0; i < ARRAY_SIZE(port_fer_saved); ++i) | |
567 | port_fer_saved[i] = *port_fer[i]; | |
568 | #endif | |
569 | ||
1efc80b5 MH |
570 | for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { |
571 | bank = gpio_bank(i); | |
572 | ||
269647dc | 573 | #if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) |
f556309e | 574 | gpio_bank_saved[bank].fer = *port_fer[bank]; |
269647dc | 575 | #if defined(CONFIG_BF52x) || defined(CONFIG_BF51x) |
f556309e | 576 | gpio_bank_saved[bank].mux = *port_mux[bank]; |
1efc80b5 | 577 | #else |
f556309e MF |
578 | if (bank == 0) |
579 | gpio_bank_saved[bank].mux = bfin_read_PORT_MUX(); | |
1efc80b5 MH |
580 | #endif |
581 | #endif | |
f556309e MF |
582 | gpio_bank_saved[bank].data = gpio_array[bank]->data; |
583 | gpio_bank_saved[bank].inen = gpio_array[bank]->inen; | |
584 | gpio_bank_saved[bank].polar = gpio_array[bank]->polar; | |
585 | gpio_bank_saved[bank].dir = gpio_array[bank]->dir; | |
586 | gpio_bank_saved[bank].edge = gpio_array[bank]->edge; | |
587 | gpio_bank_saved[bank].both = gpio_array[bank]->both; | |
588 | gpio_bank_saved[bank].maska = gpio_array[bank]->maska; | |
1efc80b5 MH |
589 | } |
590 | ||
9466a051 MF |
591 | #ifdef BFIN_SPECIAL_GPIO_BANKS |
592 | bfin_special_gpio_pm_hibernate_suspend(); | |
593 | #endif | |
594 | ||
1efc80b5 MH |
595 | AWA_DUMMY_READ(maska); |
596 | } | |
597 | ||
598 | void bfin_gpio_pm_hibernate_restore(void) | |
599 | { | |
600 | int i, bank; | |
601 | ||
9466a051 MF |
602 | #ifdef BF538_FAMILY |
603 | for (i = 0; i < ARRAY_SIZE(port_fer_saved); ++i) | |
604 | *port_fer[i] = port_fer_saved[i]; | |
605 | #endif | |
606 | ||
1efc80b5 | 607 | for (i = 0; i < MAX_BLACKFIN_GPIOS; i += GPIO_BANKSIZE) { |
f556309e | 608 | bank = gpio_bank(i); |
1efc80b5 | 609 | |
269647dc MF |
610 | #if defined(CONFIG_BF52x) || defined(BF537_FAMILY) || defined(CONFIG_BF51x) |
611 | #if defined(CONFIG_BF52x) || defined(CONFIG_BF51x) | |
f556309e | 612 | *port_mux[bank] = gpio_bank_saved[bank].mux; |
1efc80b5 | 613 | #else |
f556309e MF |
614 | if (bank == 0) |
615 | bfin_write_PORT_MUX(gpio_bank_saved[bank].mux); | |
1efc80b5 | 616 | #endif |
f556309e | 617 | *port_fer[bank] = gpio_bank_saved[bank].fer; |
1efc80b5 | 618 | #endif |
f556309e | 619 | gpio_array[bank]->inen = gpio_bank_saved[bank].inen; |
c03c2a87 MH |
620 | gpio_array[bank]->data_set = gpio_bank_saved[bank].data |
621 | & gpio_bank_saved[bank].dir; | |
f556309e MF |
622 | gpio_array[bank]->dir = gpio_bank_saved[bank].dir; |
623 | gpio_array[bank]->polar = gpio_bank_saved[bank].polar; | |
624 | gpio_array[bank]->edge = gpio_bank_saved[bank].edge; | |
625 | gpio_array[bank]->both = gpio_bank_saved[bank].both; | |
f556309e | 626 | gpio_array[bank]->maska = gpio_bank_saved[bank].maska; |
1efc80b5 | 627 | } |
9466a051 MF |
628 | |
629 | #ifdef BFIN_SPECIAL_GPIO_BANKS | |
630 | bfin_special_gpio_pm_hibernate_restore(); | |
631 | #endif | |
632 | ||
1efc80b5 MH |
633 | AWA_DUMMY_READ(maska); |
634 | } | |
635 | ||
636 | ||
1394f032 BW |
637 | #endif |
638 | ||
d2b11a46 MH |
639 | /*********************************************************** |
640 | * | |
812ae98f | 641 | * FUNCTIONS: Blackfin Peripheral Resource Allocation |
d2b11a46 MH |
642 | * and PortMux Setup |
643 | * | |
644 | * INPUTS/OUTPUTS: | |
645 | * per Peripheral Identifier | |
646 | * label String | |
647 | * | |
648 | * DESCRIPTION: Blackfin Peripheral Resource Allocation and Setup API | |
649 | * | |
650 | * CAUTION: | |
651 | ************************************************************* | |
652 | * MODIFICATION HISTORY : | |
653 | **************************************************************/ | |
654 | ||
d2b11a46 MH |
655 | int peripheral_request(unsigned short per, const char *label) |
656 | { | |
657 | unsigned long flags; | |
658 | unsigned short ident = P_IDENT(per); | |
659 | ||
660 | /* | |
661 | * Don't cares are pins with only one dedicated function | |
662 | */ | |
c58c2140 | 663 | |
d2b11a46 MH |
664 | if (per & P_DONTCARE) |
665 | return 0; | |
666 | ||
667 | if (!(per & P_DEFINED)) | |
668 | return -ENODEV; | |
669 | ||
89e84eea BS |
670 | BUG_ON(ident >= MAX_RESOURCES); |
671 | ||
3b139cdb | 672 | flags = hard_local_irq_save(); |
d2b11a46 | 673 | |
6a87d29b MF |
674 | /* If a pin can be muxed as either GPIO or peripheral, make |
675 | * sure it is not already a GPIO pin when we request it. | |
676 | */ | |
332824b8 | 677 | if (unlikely(!check_gpio(ident) && is_reserved(gpio, ident, 1))) { |
d6879c58 RG |
678 | if (system_state == SYSTEM_BOOTING) |
679 | dump_stack(); | |
d2b11a46 | 680 | printk(KERN_ERR |
6c7ec0ec | 681 | "%s: Peripheral %d is already reserved as GPIO by %s !\n", |
b85d858b | 682 | __func__, ident, get_label(ident)); |
3b139cdb | 683 | hard_local_irq_restore(flags); |
d2b11a46 MH |
684 | return -EBUSY; |
685 | } | |
686 | ||
332824b8 | 687 | if (unlikely(is_reserved(peri, ident, 1))) { |
d2b11a46 | 688 | |
d171c233 MF |
689 | /* |
690 | * Pin functions like AMC address strobes my | |
691 | * be requested and used by several drivers | |
692 | */ | |
d2b11a46 | 693 | |
6c7ec0ec | 694 | if (!(per & P_MAYSHARE)) { |
d171c233 MF |
695 | /* |
696 | * Allow that the identical pin function can | |
697 | * be requested from the same driver twice | |
698 | */ | |
d2b11a46 | 699 | |
d171c233 MF |
700 | if (cmp_label(ident, label) == 0) |
701 | goto anyway; | |
d2b11a46 | 702 | |
d6879c58 RG |
703 | if (system_state == SYSTEM_BOOTING) |
704 | dump_stack(); | |
d2b11a46 MH |
705 | printk(KERN_ERR |
706 | "%s: Peripheral %d function %d is already reserved by %s !\n", | |
b85d858b | 707 | __func__, ident, P_FUNCT2MUX(per), get_label(ident)); |
3b139cdb | 708 | hard_local_irq_restore(flags); |
d2b11a46 MH |
709 | return -EBUSY; |
710 | } | |
711 | } | |
712 | ||
05bbec38 | 713 | if (unlikely(portmux_group_check(per))) { |
714 | hard_local_irq_restore(flags); | |
715 | return -EBUSY; | |
716 | } | |
d171c233 | 717 | anyway: |
332824b8 | 718 | reserve(peri, ident); |
d2b11a46 | 719 | |
f556309e | 720 | portmux_setup(per); |
c58c2140 MH |
721 | port_setup(ident, PERIPHERAL_USAGE); |
722 | ||
3b139cdb | 723 | hard_local_irq_restore(flags); |
c58c2140 MH |
724 | set_label(ident, label); |
725 | ||
726 | return 0; | |
727 | } | |
728 | EXPORT_SYMBOL(peripheral_request); | |
729 | ||
68179371 | 730 | int peripheral_request_list(const unsigned short per[], const char *label) |
c58c2140 MH |
731 | { |
732 | u16 cnt; | |
733 | int ret; | |
734 | ||
735 | for (cnt = 0; per[cnt] != 0; cnt++) { | |
314c98d5 | 736 | |
c58c2140 | 737 | ret = peripheral_request(per[cnt], label); |
314c98d5 MH |
738 | |
739 | if (ret < 0) { | |
d171c233 | 740 | for ( ; cnt > 0; cnt--) |
314c98d5 | 741 | peripheral_free(per[cnt - 1]); |
d171c233 MF |
742 | |
743 | return ret; | |
314c98d5 | 744 | } |
c58c2140 MH |
745 | } |
746 | ||
747 | return 0; | |
748 | } | |
749 | EXPORT_SYMBOL(peripheral_request_list); | |
750 | ||
751 | void peripheral_free(unsigned short per) | |
752 | { | |
753 | unsigned long flags; | |
754 | unsigned short ident = P_IDENT(per); | |
755 | ||
756 | if (per & P_DONTCARE) | |
757 | return; | |
758 | ||
759 | if (!(per & P_DEFINED)) | |
760 | return; | |
761 | ||
3b139cdb | 762 | flags = hard_local_irq_save(); |
c58c2140 | 763 | |
332824b8 | 764 | if (unlikely(!is_reserved(peri, ident, 0))) { |
3b139cdb | 765 | hard_local_irq_restore(flags); |
c58c2140 MH |
766 | return; |
767 | } | |
768 | ||
d171c233 | 769 | if (!(per & P_MAYSHARE)) |
c58c2140 | 770 | port_setup(ident, GPIO_USAGE); |
c58c2140 | 771 | |
332824b8 | 772 | unreserve(peri, ident); |
c58c2140 | 773 | |
2acde902 MH |
774 | set_label(ident, "free"); |
775 | ||
3b139cdb | 776 | hard_local_irq_restore(flags); |
c58c2140 MH |
777 | } |
778 | EXPORT_SYMBOL(peripheral_free); | |
779 | ||
68179371 | 780 | void peripheral_free_list(const unsigned short per[]) |
c58c2140 MH |
781 | { |
782 | u16 cnt; | |
d171c233 | 783 | for (cnt = 0; per[cnt] != 0; cnt++) |
c58c2140 | 784 | peripheral_free(per[cnt]); |
c58c2140 MH |
785 | } |
786 | EXPORT_SYMBOL(peripheral_free_list); | |
787 | ||
1394f032 BW |
788 | /*********************************************************** |
789 | * | |
790 | * FUNCTIONS: Blackfin GPIO Driver | |
791 | * | |
792 | * INPUTS/OUTPUTS: | |
d2b11a46 MH |
793 | * gpio PIO Number between 0 and MAX_BLACKFIN_GPIOS |
794 | * label String | |
1394f032 BW |
795 | * |
796 | * DESCRIPTION: Blackfin GPIO Driver API | |
797 | * | |
798 | * CAUTION: | |
799 | ************************************************************* | |
800 | * MODIFICATION HISTORY : | |
801 | **************************************************************/ | |
802 | ||
a4f0b32c | 803 | int bfin_gpio_request(unsigned gpio, const char *label) |
1394f032 BW |
804 | { |
805 | unsigned long flags; | |
806 | ||
807 | if (check_gpio(gpio) < 0) | |
808 | return -EINVAL; | |
809 | ||
3b139cdb | 810 | flags = hard_local_irq_save(); |
1394f032 | 811 | |
2acde902 MH |
812 | /* |
813 | * Allow that the identical GPIO can | |
814 | * be requested from the same driver twice | |
815 | * Do nothing and return - | |
816 | */ | |
817 | ||
818 | if (cmp_label(gpio, label) == 0) { | |
3b139cdb | 819 | hard_local_irq_restore(flags); |
2acde902 MH |
820 | return 0; |
821 | } | |
822 | ||
332824b8 | 823 | if (unlikely(is_reserved(gpio, gpio, 1))) { |
d6879c58 RG |
824 | if (system_state == SYSTEM_BOOTING) |
825 | dump_stack(); | |
d2b11a46 | 826 | printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", |
9570ff4a | 827 | gpio, get_label(gpio)); |
3b139cdb | 828 | hard_local_irq_restore(flags); |
d2b11a46 MH |
829 | return -EBUSY; |
830 | } | |
332824b8 | 831 | if (unlikely(is_reserved(peri, gpio, 1))) { |
d6879c58 RG |
832 | if (system_state == SYSTEM_BOOTING) |
833 | dump_stack(); | |
d2b11a46 MH |
834 | printk(KERN_ERR |
835 | "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", | |
836 | gpio, get_label(gpio)); | |
3b139cdb | 837 | hard_local_irq_restore(flags); |
1394f032 BW |
838 | return -EBUSY; |
839 | } | |
332824b8 | 840 | if (unlikely(is_reserved(gpio_irq, gpio, 1))) { |
9570ff4a GY |
841 | printk(KERN_NOTICE "bfin-gpio: GPIO %d is already reserved as gpio-irq!" |
842 | " (Documentation/blackfin/bfin-gpio-notes.txt)\n", gpio); | |
54e4ff4d | 843 | } else { /* Reset POLAR setting when acquiring a gpio for the first time */ |
a2be3931 MH |
844 | set_gpio_polar(gpio, 0); |
845 | } | |
d2b11a46 | 846 | |
332824b8 | 847 | reserve(gpio, gpio); |
9570ff4a | 848 | set_label(gpio, label); |
1394f032 | 849 | |
3b139cdb | 850 | hard_local_irq_restore(flags); |
1394f032 BW |
851 | |
852 | port_setup(gpio, GPIO_USAGE); | |
853 | ||
854 | return 0; | |
855 | } | |
a4f0b32c | 856 | EXPORT_SYMBOL(bfin_gpio_request); |
1394f032 | 857 | |
a4f0b32c | 858 | void bfin_gpio_free(unsigned gpio) |
1394f032 BW |
859 | { |
860 | unsigned long flags; | |
861 | ||
862 | if (check_gpio(gpio) < 0) | |
863 | return; | |
864 | ||
45c4f2a0 UKK |
865 | might_sleep(); |
866 | ||
3b139cdb | 867 | flags = hard_local_irq_save(); |
1394f032 | 868 | |
332824b8 | 869 | if (unlikely(!is_reserved(gpio, gpio, 0))) { |
d6879c58 RG |
870 | if (system_state == SYSTEM_BOOTING) |
871 | dump_stack(); | |
f85c4abd | 872 | gpio_error(gpio); |
3b139cdb | 873 | hard_local_irq_restore(flags); |
1394f032 BW |
874 | return; |
875 | } | |
876 | ||
332824b8 | 877 | unreserve(gpio, gpio); |
1394f032 | 878 | |
2acde902 MH |
879 | set_label(gpio, "free"); |
880 | ||
3b139cdb | 881 | hard_local_irq_restore(flags); |
1394f032 | 882 | } |
a4f0b32c | 883 | EXPORT_SYMBOL(bfin_gpio_free); |
1394f032 | 884 | |
621dd247 | 885 | #ifdef BFIN_SPECIAL_GPIO_BANKS |
332824b8 | 886 | DECLARE_RESERVED_MAP(special_gpio, gpio_bank(MAX_RESOURCES)); |
621dd247 MH |
887 | |
888 | int bfin_special_gpio_request(unsigned gpio, const char *label) | |
889 | { | |
890 | unsigned long flags; | |
891 | ||
3b139cdb | 892 | flags = hard_local_irq_save(); |
621dd247 MH |
893 | |
894 | /* | |
895 | * Allow that the identical GPIO can | |
896 | * be requested from the same driver twice | |
897 | * Do nothing and return - | |
898 | */ | |
899 | ||
900 | if (cmp_label(gpio, label) == 0) { | |
3b139cdb | 901 | hard_local_irq_restore(flags); |
621dd247 MH |
902 | return 0; |
903 | } | |
904 | ||
332824b8 | 905 | if (unlikely(is_reserved(special_gpio, gpio, 1))) { |
3b139cdb | 906 | hard_local_irq_restore(flags); |
621dd247 MH |
907 | printk(KERN_ERR "bfin-gpio: GPIO %d is already reserved by %s !\n", |
908 | gpio, get_label(gpio)); | |
909 | ||
910 | return -EBUSY; | |
911 | } | |
332824b8 | 912 | if (unlikely(is_reserved(peri, gpio, 1))) { |
3b139cdb | 913 | hard_local_irq_restore(flags); |
621dd247 MH |
914 | printk(KERN_ERR |
915 | "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", | |
916 | gpio, get_label(gpio)); | |
917 | ||
918 | return -EBUSY; | |
919 | } | |
920 | ||
332824b8 MF |
921 | reserve(special_gpio, gpio); |
922 | reserve(peri, gpio); | |
621dd247 MH |
923 | |
924 | set_label(gpio, label); | |
3b139cdb | 925 | hard_local_irq_restore(flags); |
621dd247 MH |
926 | port_setup(gpio, GPIO_USAGE); |
927 | ||
928 | return 0; | |
929 | } | |
930 | EXPORT_SYMBOL(bfin_special_gpio_request); | |
931 | ||
932 | void bfin_special_gpio_free(unsigned gpio) | |
933 | { | |
934 | unsigned long flags; | |
935 | ||
936 | might_sleep(); | |
937 | ||
3b139cdb | 938 | flags = hard_local_irq_save(); |
621dd247 | 939 | |
332824b8 | 940 | if (unlikely(!is_reserved(special_gpio, gpio, 0))) { |
621dd247 | 941 | gpio_error(gpio); |
3b139cdb | 942 | hard_local_irq_restore(flags); |
621dd247 MH |
943 | return; |
944 | } | |
945 | ||
332824b8 MF |
946 | unreserve(special_gpio, gpio); |
947 | unreserve(peri, gpio); | |
621dd247 | 948 | set_label(gpio, "free"); |
3b139cdb | 949 | hard_local_irq_restore(flags); |
621dd247 MH |
950 | } |
951 | EXPORT_SYMBOL(bfin_special_gpio_free); | |
952 | #endif | |
953 | ||
954 | ||
9570ff4a GY |
955 | int bfin_gpio_irq_request(unsigned gpio, const char *label) |
956 | { | |
957 | unsigned long flags; | |
958 | ||
959 | if (check_gpio(gpio) < 0) | |
960 | return -EINVAL; | |
961 | ||
3b139cdb | 962 | flags = hard_local_irq_save(); |
9570ff4a | 963 | |
332824b8 | 964 | if (unlikely(is_reserved(peri, gpio, 1))) { |
d6879c58 RG |
965 | if (system_state == SYSTEM_BOOTING) |
966 | dump_stack(); | |
9570ff4a GY |
967 | printk(KERN_ERR |
968 | "bfin-gpio: GPIO %d is already reserved as Peripheral by %s !\n", | |
969 | gpio, get_label(gpio)); | |
3b139cdb | 970 | hard_local_irq_restore(flags); |
9570ff4a GY |
971 | return -EBUSY; |
972 | } | |
332824b8 | 973 | if (unlikely(is_reserved(gpio, gpio, 1))) |
9570ff4a GY |
974 | printk(KERN_NOTICE "bfin-gpio: GPIO %d is already reserved by %s! " |
975 | "(Documentation/blackfin/bfin-gpio-notes.txt)\n", | |
976 | gpio, get_label(gpio)); | |
977 | ||
332824b8 | 978 | reserve(gpio_irq, gpio); |
9570ff4a GY |
979 | set_label(gpio, label); |
980 | ||
3b139cdb | 981 | hard_local_irq_restore(flags); |
9570ff4a GY |
982 | |
983 | port_setup(gpio, GPIO_USAGE); | |
984 | ||
985 | return 0; | |
986 | } | |
987 | ||
988 | void bfin_gpio_irq_free(unsigned gpio) | |
989 | { | |
990 | unsigned long flags; | |
991 | ||
992 | if (check_gpio(gpio) < 0) | |
993 | return; | |
994 | ||
3b139cdb | 995 | flags = hard_local_irq_save(); |
9570ff4a | 996 | |
332824b8 | 997 | if (unlikely(!is_reserved(gpio_irq, gpio, 0))) { |
d6879c58 RG |
998 | if (system_state == SYSTEM_BOOTING) |
999 | dump_stack(); | |
9570ff4a | 1000 | gpio_error(gpio); |
3b139cdb | 1001 | hard_local_irq_restore(flags); |
9570ff4a GY |
1002 | return; |
1003 | } | |
1004 | ||
332824b8 | 1005 | unreserve(gpio_irq, gpio); |
9570ff4a GY |
1006 | |
1007 | set_label(gpio, "free"); | |
1008 | ||
3b139cdb | 1009 | hard_local_irq_restore(flags); |
9570ff4a GY |
1010 | } |
1011 | ||
f556309e MF |
1012 | static inline void __bfin_gpio_direction_input(unsigned gpio) |
1013 | { | |
f556309e | 1014 | gpio_array[gpio_bank(gpio)]->dir &= ~gpio_bit(gpio); |
f556309e MF |
1015 | gpio_array[gpio_bank(gpio)]->inen |= gpio_bit(gpio); |
1016 | } | |
1017 | ||
a4f0b32c | 1018 | int bfin_gpio_direction_input(unsigned gpio) |
d2b11a46 MH |
1019 | { |
1020 | unsigned long flags; | |
1021 | ||
332824b8 | 1022 | if (unlikely(!is_reserved(gpio, gpio, 0))) { |
acbcd263 MH |
1023 | gpio_error(gpio); |
1024 | return -EINVAL; | |
1025 | } | |
1026 | ||
3b139cdb | 1027 | flags = hard_local_irq_save(); |
f556309e MF |
1028 | __bfin_gpio_direction_input(gpio); |
1029 | AWA_DUMMY_READ(inen); | |
3b139cdb | 1030 | hard_local_irq_restore(flags); |
acbcd263 MH |
1031 | |
1032 | return 0; | |
d2b11a46 | 1033 | } |
a4f0b32c | 1034 | EXPORT_SYMBOL(bfin_gpio_direction_input); |
d2b11a46 | 1035 | |
f556309e | 1036 | void bfin_gpio_irq_prepare(unsigned gpio) |
d2b11a46 | 1037 | { |
f556309e | 1038 | port_setup(gpio, GPIO_USAGE); |
d2b11a46 | 1039 | } |
d2b11a46 | 1040 | |
a4f0b32c | 1041 | void bfin_gpio_set_value(unsigned gpio, int arg) |
d2b11a46 MH |
1042 | { |
1043 | if (arg) | |
f556309e | 1044 | gpio_array[gpio_bank(gpio)]->data_set = gpio_bit(gpio); |
d2b11a46 | 1045 | else |
f556309e | 1046 | gpio_array[gpio_bank(gpio)]->data_clear = gpio_bit(gpio); |
d2b11a46 | 1047 | } |
a4f0b32c | 1048 | EXPORT_SYMBOL(bfin_gpio_set_value); |
d2b11a46 | 1049 | |
f556309e | 1050 | int bfin_gpio_direction_output(unsigned gpio, int value) |
affee2b2 MH |
1051 | { |
1052 | unsigned long flags; | |
1053 | ||
332824b8 | 1054 | if (unlikely(!is_reserved(gpio, gpio, 0))) { |
f556309e MF |
1055 | gpio_error(gpio); |
1056 | return -EINVAL; | |
1057 | } | |
affee2b2 | 1058 | |
3b139cdb | 1059 | flags = hard_local_irq_save(); |
affee2b2 | 1060 | |
f556309e MF |
1061 | gpio_array[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio); |
1062 | gpio_set_value(gpio, value); | |
f556309e | 1063 | gpio_array[gpio_bank(gpio)]->dir |= gpio_bit(gpio); |
f556309e MF |
1064 | |
1065 | AWA_DUMMY_READ(dir); | |
3b139cdb | 1066 | hard_local_irq_restore(flags); |
f556309e MF |
1067 | |
1068 | return 0; | |
1069 | } | |
1070 | EXPORT_SYMBOL(bfin_gpio_direction_output); | |
d2b11a46 | 1071 | |
a4f0b32c | 1072 | int bfin_gpio_get_value(unsigned gpio) |
803a8d2a MH |
1073 | { |
1074 | unsigned long flags; | |
803a8d2a MH |
1075 | |
1076 | if (unlikely(get_gpio_edge(gpio))) { | |
f556309e | 1077 | int ret; |
3b139cdb | 1078 | flags = hard_local_irq_save(); |
803a8d2a MH |
1079 | set_gpio_edge(gpio, 0); |
1080 | ret = get_gpio_data(gpio); | |
1081 | set_gpio_edge(gpio, 1); | |
3b139cdb | 1082 | hard_local_irq_restore(flags); |
803a8d2a MH |
1083 | return ret; |
1084 | } else | |
1085 | return get_gpio_data(gpio); | |
1086 | } | |
a4f0b32c | 1087 | EXPORT_SYMBOL(bfin_gpio_get_value); |
803a8d2a | 1088 | |
168f1212 MF |
1089 | /* If we are booting from SPI and our board lacks a strong enough pull up, |
1090 | * the core can reset and execute the bootrom faster than the resistor can | |
1091 | * pull the signal logically high. To work around this (common) error in | |
1092 | * board design, we explicitly set the pin back to GPIO mode, force /CS | |
1093 | * high, and wait for the electrons to do their thing. | |
1094 | * | |
1095 | * This function only makes sense to be called from reset code, but it | |
1096 | * lives here as we need to force all the GPIO states w/out going through | |
1097 | * BUG() checks and such. | |
1098 | */ | |
b52dae31 | 1099 | void bfin_reset_boot_spi_cs(unsigned short pin) |
168f1212 | 1100 | { |
b52dae31 | 1101 | unsigned short gpio = P_IDENT(pin); |
4d5f4ed3 | 1102 | port_setup(gpio, GPIO_USAGE); |
f556309e | 1103 | gpio_array[gpio_bank(gpio)]->data_set = gpio_bit(gpio); |
a2c8cfef | 1104 | AWA_DUMMY_READ(data_set); |
168f1212 MF |
1105 | udelay(1); |
1106 | } | |
d2b11a46 | 1107 | |
1545a111 | 1108 | #if defined(CONFIG_PROC_FS) |
6362ec27 | 1109 | static int gpio_proc_show(struct seq_file *m, void *v) |
1545a111 | 1110 | { |
6362ec27 | 1111 | int c, irq, gpio; |
1545a111 MF |
1112 | |
1113 | for (c = 0; c < MAX_RESOURCES; c++) { | |
332824b8 MF |
1114 | irq = is_reserved(gpio_irq, c, 1); |
1115 | gpio = is_reserved(gpio, c, 1); | |
9570ff4a | 1116 | if (!check_gpio(c) && (gpio || irq)) |
6362ec27 | 1117 | seq_printf(m, "GPIO_%d: \t%s%s \t\tGPIO %s\n", c, |
9570ff4a GY |
1118 | get_label(c), (gpio && irq) ? " *" : "", |
1119 | get_gpio_dir(c) ? "OUTPUT" : "INPUT"); | |
332824b8 | 1120 | else if (is_reserved(peri, c, 1)) |
6362ec27 | 1121 | seq_printf(m, "GPIO_%d: \t%s \t\tPeripheral\n", c, get_label(c)); |
1545a111 MF |
1122 | else |
1123 | continue; | |
1545a111 | 1124 | } |
6362ec27 AD |
1125 | |
1126 | return 0; | |
1545a111 MF |
1127 | } |
1128 | ||
6362ec27 AD |
1129 | static int gpio_proc_open(struct inode *inode, struct file *file) |
1130 | { | |
1131 | return single_open(file, gpio_proc_show, NULL); | |
1132 | } | |
1133 | ||
1134 | static const struct file_operations gpio_proc_ops = { | |
1135 | .open = gpio_proc_open, | |
1136 | .read = seq_read, | |
1137 | .llseek = seq_lseek, | |
1138 | .release = single_release, | |
1139 | }; | |
1140 | ||
1545a111 MF |
1141 | static __init int gpio_register_proc(void) |
1142 | { | |
1143 | struct proc_dir_entry *proc_gpio; | |
1144 | ||
ce860914 SM |
1145 | proc_gpio = proc_create("gpio", 0, NULL, &gpio_proc_ops); |
1146 | return proc_gpio == NULL; | |
1545a111 | 1147 | } |
1545a111 MF |
1148 | __initcall(gpio_register_proc); |
1149 | #endif | |
a4f0b32c MH |
1150 | |
1151 | #ifdef CONFIG_GPIOLIB | |
f9c29e87 | 1152 | static int bfin_gpiolib_direction_input(struct gpio_chip *chip, unsigned gpio) |
a4f0b32c MH |
1153 | { |
1154 | return bfin_gpio_direction_input(gpio); | |
1155 | } | |
1156 | ||
f9c29e87 | 1157 | static int bfin_gpiolib_direction_output(struct gpio_chip *chip, unsigned gpio, int level) |
a4f0b32c MH |
1158 | { |
1159 | return bfin_gpio_direction_output(gpio, level); | |
1160 | } | |
1161 | ||
f9c29e87 | 1162 | static int bfin_gpiolib_get_value(struct gpio_chip *chip, unsigned gpio) |
a4f0b32c | 1163 | { |
48295fe9 | 1164 | return !!bfin_gpio_get_value(gpio); |
a4f0b32c MH |
1165 | } |
1166 | ||
f9c29e87 | 1167 | static void bfin_gpiolib_set_value(struct gpio_chip *chip, unsigned gpio, int value) |
a4f0b32c | 1168 | { |
a4f0b32c | 1169 | return bfin_gpio_set_value(gpio, value); |
a4f0b32c MH |
1170 | } |
1171 | ||
f9c29e87 | 1172 | static int bfin_gpiolib_gpio_request(struct gpio_chip *chip, unsigned gpio) |
a4f0b32c MH |
1173 | { |
1174 | return bfin_gpio_request(gpio, chip->label); | |
1175 | } | |
1176 | ||
f9c29e87 | 1177 | static void bfin_gpiolib_gpio_free(struct gpio_chip *chip, unsigned gpio) |
a4f0b32c MH |
1178 | { |
1179 | return bfin_gpio_free(gpio); | |
1180 | } | |
1181 | ||
f9c29e87 | 1182 | static int bfin_gpiolib_gpio_to_irq(struct gpio_chip *chip, unsigned gpio) |
7f4f69f9 JE |
1183 | { |
1184 | return gpio + GPIO_IRQ_BASE; | |
1185 | } | |
1186 | ||
a4f0b32c | 1187 | static struct gpio_chip bfin_chip = { |
edd07992 | 1188 | .label = "BFIN-GPIO", |
a4f0b32c MH |
1189 | .direction_input = bfin_gpiolib_direction_input, |
1190 | .get = bfin_gpiolib_get_value, | |
1191 | .direction_output = bfin_gpiolib_direction_output, | |
1192 | .set = bfin_gpiolib_set_value, | |
1193 | .request = bfin_gpiolib_gpio_request, | |
1194 | .free = bfin_gpiolib_gpio_free, | |
7f4f69f9 | 1195 | .to_irq = bfin_gpiolib_gpio_to_irq, |
a4f0b32c MH |
1196 | .base = 0, |
1197 | .ngpio = MAX_BLACKFIN_GPIOS, | |
1198 | }; | |
1199 | ||
1200 | static int __init bfin_gpiolib_setup(void) | |
1201 | { | |
03be35d1 | 1202 | return gpiochip_add_data(&bfin_chip, NULL); |
a4f0b32c MH |
1203 | } |
1204 | arch_initcall(bfin_gpiolib_setup); | |
1205 | #endif |