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