diff options
| -rw-r--r-- | arch/blackfin/kernel/bfin_gpio.c | 185 |
1 files changed, 118 insertions, 67 deletions
diff --git a/arch/blackfin/kernel/bfin_gpio.c b/arch/blackfin/kernel/bfin_gpio.c index ca1c1f9debd6..170cf90735ba 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 |
| 218 | static struct { | 218 | static 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 | ||
| 265 | static void portmux_setup(unsigned short per) | 246 | static 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 | |||
| 279 | static 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) |
| 289 | inline void portmux_setup(unsigned short per) | 298 | inline 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 | ||
| 303 | inline u16 get_portmux(unsigned short per) | 312 | inline 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 | } |
| 318 | static 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) |
| 323 | static 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; | ||
