1 /* 2 * ADI GPIO2 Abstraction Layer 3 * Support BF54x, BF60x and future processors. 4 * 5 * Copyright 2008-2013 Analog Devices Inc. 6 * 7 * Licensed under the GPL-2 or later 8 */ 9 10 #include <common.h> 11 #include <asm/errno.h> 12 #include <asm/gpio.h> 13 #include <asm/portmux.h> 14 15 static struct gpio_port_t * const gpio_array[] = { 16 (struct gpio_port_t *)PORTA_FER, 17 (struct gpio_port_t *)PORTB_FER, 18 (struct gpio_port_t *)PORTC_FER, 19 (struct gpio_port_t *)PORTD_FER, 20 (struct gpio_port_t *)PORTE_FER, 21 (struct gpio_port_t *)PORTF_FER, 22 (struct gpio_port_t *)PORTG_FER, 23 #if defined(CONFIG_BF54x) 24 (struct gpio_port_t *)PORTH_FER, 25 (struct gpio_port_t *)PORTI_FER, 26 (struct gpio_port_t *)PORTJ_FER, 27 #endif 28 }; 29 30 #define RESOURCE_LABEL_SIZE 16 31 32 static struct str_ident { 33 char name[RESOURCE_LABEL_SIZE]; 34 } str_ident[MAX_RESOURCES]; 35 36 static void gpio_error(unsigned gpio) 37 { 38 printf("adi_gpio2: GPIO %d wasn't requested!\n", gpio); 39 } 40 41 static void set_label(unsigned short ident, const char *label) 42 { 43 if (label) { 44 strncpy(str_ident[ident].name, label, 45 RESOURCE_LABEL_SIZE); 46 str_ident[ident].name[RESOURCE_LABEL_SIZE - 1] = 0; 47 } 48 } 49 50 static char *get_label(unsigned short ident) 51 { 52 return *str_ident[ident].name ? str_ident[ident].name : "UNKNOWN"; 53 } 54 55 static int cmp_label(unsigned short ident, const char *label) 56 { 57 if (label == NULL) 58 printf("adi_gpio2: please provide none-null label\n"); 59 60 if (label) 61 return strcmp(str_ident[ident].name, label); 62 else 63 return -EINVAL; 64 } 65 66 #define map_entry(m, i) reserved_##m##_map[gpio_bank(i)] 67 #define is_reserved(m, i, e) (map_entry(m, i) & gpio_bit(i)) 68 #define reserve(m, i) (map_entry(m, i) |= gpio_bit(i)) 69 #define unreserve(m, i) (map_entry(m, i) &= ~gpio_bit(i)) 70 #define DECLARE_RESERVED_MAP(m, c) unsigned short reserved_##m##_map[c] 71 72 static DECLARE_RESERVED_MAP(gpio, GPIO_BANK_NUM); 73 static DECLARE_RESERVED_MAP(peri, gpio_bank(MAX_RESOURCES)); 74 75 inline int check_gpio(unsigned gpio) 76 { 77 #if defined(CONFIG_BF54x) 78 if (gpio == GPIO_PB15 || gpio == GPIO_PC14 || gpio == GPIO_PC15 || 79 gpio == GPIO_PH14 || gpio == GPIO_PH15 || 80 gpio == GPIO_PJ14 || gpio == GPIO_PJ15) 81 return -EINVAL; 82 #endif 83 if (gpio >= MAX_GPIOS) 84 return -EINVAL; 85 return 0; 86 } 87 88 static void port_setup(unsigned gpio, unsigned short usage) 89 { 90 #if defined(CONFIG_BF54x) 91 if (usage == GPIO_USAGE) 92 gpio_array[gpio_bank(gpio)]->port_fer &= ~gpio_bit(gpio); 93 else 94 gpio_array[gpio_bank(gpio)]->port_fer |= gpio_bit(gpio); 95 #else 96 if (usage == GPIO_USAGE) 97 gpio_array[gpio_bank(gpio)]->port_fer_clear = gpio_bit(gpio); 98 else 99 gpio_array[gpio_bank(gpio)]->port_fer_set = gpio_bit(gpio); 100 #endif 101 SSYNC(); 102 } 103 104 inline void portmux_setup(unsigned short per) 105 { 106 u32 pmux; 107 u16 ident = P_IDENT(per); 108 u16 function = P_FUNCT2MUX(per); 109 110 pmux = gpio_array[gpio_bank(ident)]->port_mux; 111 112 pmux &= ~(0x3 << (2 * gpio_sub_n(ident))); 113 pmux |= (function & 0x3) << (2 * gpio_sub_n(ident)); 114 115 gpio_array[gpio_bank(ident)]->port_mux = pmux; 116 } 117 118 inline u16 get_portmux(unsigned short per) 119 { 120 u32 pmux; 121 u16 ident = P_IDENT(per); 122 123 pmux = gpio_array[gpio_bank(ident)]->port_mux; 124 125 return pmux >> (2 * gpio_sub_n(ident)) & 0x3; 126 } 127 128 unsigned short get_gpio_dir(unsigned gpio) 129 { 130 return 0x01 & 131 (gpio_array[gpio_bank(gpio)]->dir_clear >> gpio_sub_n(gpio)); 132 } 133 134 /*********************************************************** 135 * 136 * FUNCTIONS: Peripheral Resource Allocation 137 * and PortMux Setup 138 * 139 * INPUTS/OUTPUTS: 140 * per Peripheral Identifier 141 * label String 142 * 143 * DESCRIPTION: Peripheral Resource Allocation and Setup API 144 **************************************************************/ 145 146 int peripheral_request(unsigned short per, const char *label) 147 { 148 unsigned short ident = P_IDENT(per); 149 150 /* 151 * Don't cares are pins with only one dedicated function 152 */ 153 154 if (per & P_DONTCARE) 155 return 0; 156 157 if (!(per & P_DEFINED)) 158 return -ENODEV; 159 160 BUG_ON(ident >= MAX_RESOURCES); 161 162 /* If a pin can be muxed as either GPIO or peripheral, make 163 * sure it is not already a GPIO pin when we request it. 164 */ 165 if (unlikely(!check_gpio(ident) && is_reserved(gpio, ident, 1))) { 166 printf("%s: Peripheral %d is already reserved as GPIO by %s!\n", 167 __func__, ident, get_label(ident)); 168 return -EBUSY; 169 } 170 171 if (unlikely(is_reserved(peri, ident, 1))) { 172 /* 173 * Pin functions like AMC address strobes my 174 * be requested and used by several drivers 175 */ 176 177 if (!((per & P_MAYSHARE) && 178 get_portmux(per) == P_FUNCT2MUX(per))) { 179 /* 180 * Allow that the identical pin function can 181 * be requested from the same driver twice 182 */ 183 184 if (cmp_label(ident, label) == 0) 185 goto anyway; 186 187 printf("%s: Peripheral %d function %d is already " 188 "reserved by %s!\n", __func__, ident, 189 P_FUNCT2MUX(per), get_label(ident)); 190 return -EBUSY; 191 } 192 } 193 194 anyway: 195 reserve(peri, ident); 196 197 portmux_setup(per); 198 port_setup(ident, PERIPHERAL_USAGE); 199 200 set_label(ident, label); 201 202 return 0; 203 } 204 205 int peripheral_request_list(const unsigned short per[], const char *label) 206 { 207 u16 cnt; 208 int ret; 209 210 for (cnt = 0; per[cnt] != 0; cnt++) { 211 ret = peripheral_request(per[cnt], label); 212 213 if (ret < 0) { 214 for (; cnt > 0; cnt--) 215 peripheral_free(per[cnt - 1]); 216 217 return ret; 218 } 219 } 220 221 return 0; 222 } 223 224 void peripheral_free(unsigned short per) 225 { 226 unsigned short ident = P_IDENT(per); 227 228 if (per & P_DONTCARE) 229 return; 230 231 if (!(per & P_DEFINED)) 232 return; 233 234 if (unlikely(!is_reserved(peri, ident, 0))) 235 return; 236 237 if (!(per & P_MAYSHARE)) 238 port_setup(ident, GPIO_USAGE); 239 240 unreserve(peri, ident); 241 242 set_label(ident, "free"); 243 } 244 245 void peripheral_free_list(const unsigned short per[]) 246 { 247 u16 cnt; 248 for (cnt = 0; per[cnt] != 0; cnt++) 249 peripheral_free(per[cnt]); 250 } 251 252 /*********************************************************** 253 * 254 * FUNCTIONS: GPIO Driver 255 * 256 * INPUTS/OUTPUTS: 257 * gpio PIO Number between 0 and MAX_GPIOS 258 * label String 259 * 260 * DESCRIPTION: GPIO Driver API 261 **************************************************************/ 262 263 int gpio_request(unsigned gpio, const char *label) 264 { 265 if (check_gpio(gpio) < 0) 266 return -EINVAL; 267 268 /* 269 * Allow that the identical GPIO can 270 * be requested from the same driver twice 271 * Do nothing and return - 272 */ 273 274 if (cmp_label(gpio, label) == 0) 275 return 0; 276 277 if (unlikely(is_reserved(gpio, gpio, 1))) { 278 printf("adi_gpio2: GPIO %d is already reserved by %s!\n", 279 gpio, get_label(gpio)); 280 return -EBUSY; 281 } 282 if (unlikely(is_reserved(peri, gpio, 1))) { 283 printf("adi_gpio2: GPIO %d is already reserved as Peripheral " 284 "by %s!\n", gpio, get_label(gpio)); 285 return -EBUSY; 286 } 287 288 reserve(gpio, gpio); 289 set_label(gpio, label); 290 291 port_setup(gpio, GPIO_USAGE); 292 293 return 0; 294 } 295 296 int gpio_free(unsigned gpio) 297 { 298 if (check_gpio(gpio) < 0) 299 return -1; 300 301 if (unlikely(!is_reserved(gpio, gpio, 0))) { 302 gpio_error(gpio); 303 return -1; 304 } 305 306 unreserve(gpio, gpio); 307 308 set_label(gpio, "free"); 309 310 return 0; 311 } 312 313 #ifdef ADI_SPECIAL_GPIO_BANKS 314 static DECLARE_RESERVED_MAP(special_gpio, gpio_bank(MAX_RESOURCES)); 315 316 int special_gpio_request(unsigned gpio, const char *label) 317 { 318 /* 319 * Allow that the identical GPIO can 320 * be requested from the same driver twice 321 * Do nothing and return - 322 */ 323 324 if (cmp_label(gpio, label) == 0) 325 return 0; 326 327 if (unlikely(is_reserved(special_gpio, gpio, 1))) { 328 printf("adi_gpio2: GPIO %d is already reserved by %s!\n", 329 gpio, get_label(gpio)); 330 return -EBUSY; 331 } 332 if (unlikely(is_reserved(peri, gpio, 1))) { 333 printf("adi_gpio2: GPIO %d is already reserved as Peripheral " 334 "by %s!\n", gpio, get_label(gpio)); 335 336 return -EBUSY; 337 } 338 339 reserve(special_gpio, gpio); 340 reserve(peri, gpio); 341 342 set_label(gpio, label); 343 port_setup(gpio, GPIO_USAGE); 344 345 return 0; 346 } 347 348 void special_gpio_free(unsigned gpio) 349 { 350 if (unlikely(!is_reserved(special_gpio, gpio, 0))) { 351 gpio_error(gpio); 352 return; 353 } 354 355 reserve(special_gpio, gpio); 356 reserve(peri, gpio); 357 set_label(gpio, "free"); 358 } 359 #endif 360 361 static inline void __gpio_direction_input(unsigned gpio) 362 { 363 gpio_array[gpio_bank(gpio)]->dir_clear = gpio_bit(gpio); 364 #if defined(CONFIG_BF54x) 365 gpio_array[gpio_bank(gpio)]->inen |= gpio_bit(gpio); 366 #else 367 gpio_array[gpio_bank(gpio)]->inen_set = gpio_bit(gpio); 368 #endif 369 } 370 371 int gpio_direction_input(unsigned gpio) 372 { 373 unsigned long flags; 374 375 if (!is_reserved(gpio, gpio, 0)) { 376 gpio_error(gpio); 377 return -EINVAL; 378 } 379 380 local_irq_save(flags); 381 __gpio_direction_input(gpio); 382 local_irq_restore(flags); 383 384 return 0; 385 } 386 387 int gpio_set_value(unsigned gpio, int arg) 388 { 389 if (arg) 390 gpio_array[gpio_bank(gpio)]->data_set = gpio_bit(gpio); 391 else 392 gpio_array[gpio_bank(gpio)]->data_clear = gpio_bit(gpio); 393 394 return 0; 395 } 396 397 int gpio_direction_output(unsigned gpio, int value) 398 { 399 unsigned long flags; 400 401 if (!is_reserved(gpio, gpio, 0)) { 402 gpio_error(gpio); 403 return -EINVAL; 404 } 405 406 local_irq_save(flags); 407 408 #if defined(CONFIG_BF54x) 409 gpio_array[gpio_bank(gpio)]->inen &= ~gpio_bit(gpio); 410 #else 411 gpio_array[gpio_bank(gpio)]->inen_clear = gpio_bit(gpio); 412 #endif 413 gpio_set_value(gpio, value); 414 gpio_array[gpio_bank(gpio)]->dir_set = gpio_bit(gpio); 415 416 local_irq_restore(flags); 417 418 return 0; 419 } 420 421 int gpio_get_value(unsigned gpio) 422 { 423 return 1 & (gpio_array[gpio_bank(gpio)]->data >> gpio_sub_n(gpio)); 424 } 425 426 void gpio_labels(void) 427 { 428 int c, gpio; 429 430 for (c = 0; c < MAX_RESOURCES; c++) { 431 gpio = is_reserved(gpio, c, 1); 432 if (!check_gpio(c) && gpio) 433 printf("GPIO_%d:\t%s\tGPIO %s\n", c, get_label(c), 434 get_gpio_dir(c) ? "OUTPUT" : "INPUT"); 435 else if (is_reserved(peri, c, 1)) 436 printf("GPIO_%d:\t%s\tPeripheral\n", c, get_label(c)); 437 else 438 continue; 439 } 440 } 441