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