aboutsummaryrefslogtreecommitdiffstats
path: root/arch/blackfin
diff options
context:
space:
mode:
authorsteven miao <realmz6@gmail.com>2010-09-16 23:03:17 -0400
committerMike Frysinger <vapier@gentoo.org>2010-10-22 04:02:01 -0400
commit05bbec38dbafa60583be8347dea88919d48cc733 (patch)
treed172eb120912c9656357781d9f131a95a455bc99 /arch/blackfin
parenta71159b96a210d3e4d9bd24dd21278aa29770e9d (diff)
Blackfin: gpio: add peripheral group check
Many Blackfin parts group sets of pins into a single functional unit. This means you cannot use different pins within a group for different peripherals. Our resource conflict checking thus far has been limited to individual pins, so if someone tried to grab a different pin from the same group, it would be allowed while silently changing the other pins in the same group. One common example is the pin set PG12 - PG15 on BF51x parts. They may either be used with SPI0 (1st function), or they may be used with PTP/PWM/AMS3 (3rd function). Ideally, we'd like to use PG12 - PG14 for SPI0 while using PG15 with AMS3, but the hardware does not permit this. In the past, the software would allow the pins to be requested this way, but ultimately things like the Blackfin SPI driver would stop working when the hardware rerouted to a different peripheral. Signed-off-by: steven miao <realmz6@gmail.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org>
Diffstat (limited to 'arch/blackfin')
-rw-r--r--arch/blackfin/kernel/bfin_gpio.c185
1 files changed, 118 insertions, 67 deletions
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c
index ca1c1f9debd..170cf90735b 100644
--- a/arch/blackfin/kernel/bfin_gpio.c
+++ b/arch/blackfin/kernel/bfin_gpio.c
@@ -1,7 +1,7 @@
1/* 1/*
2 * GPIO Abstraction Layer 2 * GPIO Abstraction Layer
3 * 3 *
4 * Copyright 2006-2009 Analog Devices Inc. 4 * Copyright 2006-2010 Analog Devices Inc.
5 * 5 *
6 * Licensed under the GPL-2 or later 6 * Licensed under the GPL-2 or later
7 */ 7 */
@@ -215,82 +215,91 @@ static void port_setup(unsigned gpio, unsigned short usage)
215} 215}
216 216
217#ifdef BF537_FAMILY 217#ifdef BF537_FAMILY
218static struct { 218static const s8 port_mux[] = {
219 unsigned short res; 219 [GPIO_PF0] = 3,
220 unsigned short offset; 220 [GPIO_PF1] = 3,
221} port_mux_lut[] = { 221 [GPIO_PF2] = 4,
222 {.res = P_PPI0_D13, .offset = 11}, 222 [GPIO_PF3] = 4,
223 {.res = P_PPI0_D14, .offset = 11}, 223 [GPIO_PF4] = 5,
224 {.res = P_PPI0_D15, .offset = 11}, 224 [GPIO_PF5] = 6,
225 {.res = P_SPORT1_TFS, .offset = 11}, 225 [GPIO_PF6] = 7,
226 {.res = P_SPORT1_TSCLK, .offset = 11}, 226 [GPIO_PF7] = 8,
227 {.res = P_SPORT1_DTPRI, .offset = 11}, 227 [GPIO_PF8 ... GPIO_PF15] = -1,
228 {.res = P_PPI0_D10, .offset = 10}, 228 [GPIO_PG0 ... GPIO_PG7] = -1,
229 {.res = P_PPI0_D11, .offset = 10}, 229 [GPIO_PG8] = 9,
230 {.res = P_PPI0_D12, .offset = 10}, 230 [GPIO_PG9] = 9,
231 {.res = P_SPORT1_RSCLK, .offset = 10}, 231 [GPIO_PG10] = 10,
232 {.res = P_SPORT1_RFS, .offset = 10}, 232 [GPIO_PG11] = 10,
233 {.res = P_SPORT1_DRPRI, .offset = 10}, 233 [GPIO_PG12] = 10,
234 {.res = P_PPI0_D8, .offset = 9}, 234 [GPIO_PG13] = 11,
235 {.res = P_PPI0_D9, .offset = 9}, 235 [GPIO_PG14] = 11,
236 {.res = P_SPORT1_DRSEC, .offset = 9}, 236 [GPIO_PG15] = 11,
237 {.res = P_SPORT1_DTSEC, .offset = 9}, 237 [GPIO_PH0 ... GPIO_PH15] = -1,
238 {.res = P_TMR2, .offset = 8}, 238 [PORT_PJ0 ... PORT_PJ3] = -1,
239 {.res = P_PPI0_FS3, .offset = 8}, 239 [PORT_PJ4] = 1,
240 {.res = P_TMR3, .offset = 7}, 240 [PORT_PJ5] = 1,
241 {.res = P_SPI0_SSEL4, .offset = 7}, 241 [PORT_PJ6 ... PORT_PJ9] = -1,
242 {.res = P_TMR4, .offset = 6}, 242 [PORT_PJ10] = 0,
243 {.res = P_SPI0_SSEL5, .offset = 6}, 243 [PORT_PJ11] = 0,
244 {.res = P_TMR5, .offset = 5},
245 {.res = P_SPI0_SSEL6, .offset = 5},
246 {.res = P_UART1_RX, .offset = 4},
247 {.res = P_UART1_TX, .offset = 4},
248 {.res = P_TMR6, .offset = 4},
249 {.res = P_TMR7, .offset = 4},
250 {.res = P_UART0_RX, .offset = 3},
251 {.res = P_UART0_TX, .offset = 3},
252 {.res = P_DMAR0, .offset = 3},
253 {.res = P_DMAR1, .offset = 3},
254 {.res = P_SPORT0_DTSEC, .offset = 1},
255 {.res = P_SPORT0_DRSEC, .offset = 1},
256 {.res = P_CAN0_RX, .offset = 1},
257 {.res = P_CAN0_TX, .offset = 1},
258 {.res = P_SPI0_SSEL7, .offset = 1},
259 {.res = P_SPORT0_TFS, .offset = 0},
260 {.res = P_SPORT0_DTPRI, .offset = 0},
261 {.res = P_SPI0_SSEL2, .offset = 0},
262 {.res = P_SPI0_SSEL3, .offset = 0},
263}; 244};
264 245
265static void portmux_setup(unsigned short per) 246static int portmux_group_check(unsigned short per)
266{ 247{
267 u16 y, offset, muxreg; 248 u16 ident = P_IDENT(per);
268 u16 function = P_FUNCT2MUX(per); 249 u16 function = P_FUNCT2MUX(per);
250 s8 offset = port_mux[ident];
251 u16 m, pmux, pfunc;
269 252
270 for (y = 0; y < ARRAY_SIZE(port_mux_lut); y++) { 253 if (offset < 0)
271 if (port_mux_lut[y].res == per) { 254 return 0;
272
273 /* SET PORTMUX REG */
274
275 offset = port_mux_lut[y].offset;
276 muxreg = bfin_read_PORT_MUX();
277 255
278 if (offset != 1) 256 pmux = bfin_read_PORT_MUX();
279 muxreg &= ~(1 << offset); 257 for (m = 0; m < ARRAY_SIZE(port_mux); ++m) {
280 else 258 if (m == ident)
281 muxreg &= ~(3 << 1); 259 continue;
260 if (port_mux[m] != offset)
261 continue;
262 if (!is_reserved(peri, m, 1))
263 continue;
282 264
283 muxreg |= (function << offset); 265 if (offset == 1)
284 bfin_write_PORT_MUX(muxreg); 266 pfunc = (pmux >> offset) & 3;
267 else
268 pfunc = (pmux >> offset) & 1;
269 if (pfunc != function) {
270 pr_err("pin group conflict! request pin %d func %d conflict with pin %d func %d\n",
271 ident, function, m, pfunc);
272 return -EINVAL;
285 } 273 }
286 } 274 }
275
276 return 0;
277}
278
279static void portmux_setup(unsigned short per)
280{
281 u16 ident = P_IDENT(per);
282 u16 function = P_FUNCT2MUX(per);
283 s8 offset = port_mux[ident];
284 u16 pmux;
285
286 if (offset == -1)
287 return;
288
289 pmux = bfin_read_PORT_MUX();
290 if (offset != 1)
291 pmux &= ~(1 << offset);
292 else
293 pmux &= ~(3 << 1);
294 pmux |= (function << offset);
295 bfin_write_PORT_MUX(pmux);
287} 296}
288#elif defined(CONFIG_BF54x) 297#elif defined(CONFIG_BF54x)
289inline void portmux_setup(unsigned short per) 298inline void portmux_setup(unsigned short per)
290{ 299{
291 u32 pmux;
292 u16 ident = P_IDENT(per); 300 u16 ident = P_IDENT(per);
293 u16 function = P_FUNCT2MUX(per); 301 u16 function = P_FUNCT2MUX(per);
302 u32 pmux;
294 303
295 pmux = gpio_array[gpio_bank(ident)]->port_mux; 304 pmux = gpio_array[gpio_bank(ident)]->port_mux;
296 305
@@ -302,20 +311,54 @@ inline void portmux_setup(unsigned short per)
302 311
303inline u16 get_portmux(unsigned short per) 312inline u16 get_portmux(unsigned short per)
304{ 313{
305 u32 pmux;
306 u16 ident = P_IDENT(per); 314 u16 ident = P_IDENT(per);
307 315 u32 pmux = gpio_array[gpio_bank(ident)]->port_mux;
308 pmux = gpio_array[gpio_bank(ident)]->port_mux;
309
310 return (pmux >> (2 * gpio_sub_n(ident)) & 0x3); 316 return (pmux >> (2 * gpio_sub_n(ident)) & 0x3);
311} 317}
318static int portmux_group_check(unsigned short per)
319{
320 return 0;
321}
312#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x) 322#elif defined(CONFIG_BF52x) || defined(CONFIG_BF51x)
323static int portmux_group_check(unsigned short per)
324{
325 u16 ident = P_IDENT(per);
326 u16 function = P_FUNCT2MUX(per);
327 u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)];
328 u16 pin, gpiopin, pfunc;
329
330 for (pin = 0; pin < GPIO_BANKSIZE; ++pin) {
331 if (offset != pmux_offset[gpio_bank(ident)][pin])
332 continue;
333
334 gpiopin = gpio_bank(ident) * GPIO_BANKSIZE + pin;
335 if (gpiopin == ident)
336 continue;
337 if (!is_reserved(peri, gpiopin, 1))
338 continue;
339
340 pfunc = *port_mux[gpio_bank(ident)];
341 pfunc = (pfunc >> offset) & 3;
342 if (pfunc != function) {
343 pr_err("pin group conflict! request pin %d func %d conflict with pin %d func %d\n",
344 ident, function, gpiopin, pfunc);
345 return -EINVAL;
346 }
347 }
348
349 return 0;
350}
351
313inline void portmux_setup(unsigned short per) 352inline void portmux_setup(unsigned short per)
314{ 353{
315 u16 pmux, ident = P_IDENT(per), function = P_FUNCT2MUX(per); 354 u16 ident = P_IDENT(per);
355 u16 function = P_FUNCT2MUX(per);
316 u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)]; 356 u8 offset = pmux_offset[gpio_bank(ident)][gpio_sub_n(ident)];
357 u16 pmux;
317 358
318 pmux = *port_mux[gpio_bank(ident)]; 359 pmux = *port_mux[gpio_bank(ident)];
360 if (((pmux >> offset) & 3) == function)
361 return;
319 pmux &= ~(3 << offset); 362 pmux &= ~(3 << offset);
320 pmux |= (function & 3) << offset; 363 pmux |= (function & 3) << offset;
321 *port_mux[gpio_bank(ident)] = pmux; 364 *port_mux[gpio_bank(ident)] = pmux;
@@ -323,6 +366,10 @@ inline void portmux_setup(unsigned short per)
323} 366}
324#else 367#else
325# define portmux_setup(...) do { } while (0) 368# define portmux_setup(...) do { } while (0)
369static int portmux_group_check(unsigned short per)
370{
371 return 0;
372}
326#endif 373#endif
327 374
328#ifndef CONFIG_BF54x 375#ifndef CONFIG_BF54x
@@ -735,6 +782,10 @@ int peripheral_request(unsigned short per, const char *label)
735 } 782 }
736 } 783 }
737 784
785 if (unlikely(portmux_group_check(per))) {
786 hard_local_irq_restore(flags);
787 return -EBUSY;
788 }
738 anyway: 789 anyway:
739 reserve(peri, ident); 790 reserve(peri, ident);
740 791