uboot/drivers/gpio/db8500_gpio.c
<<
>>
Prefs
   1/*
   2 * Code ported from Nomadik GPIO driver in ST-Ericsson Linux kernel code.
   3 * The purpose is that GPIO config found in kernel should work by simply
   4 * copy-paste it to U-boot.
   5 *
   6 * Original Linux authors:
   7 * Copyright (C) 2008,2009 STMicroelectronics
   8 * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
   9 *   Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
  10 *
  11 * Ported to U-boot by:
  12 * Copyright (C) 2010 Joakim Axelsson <joakim.axelsson AT stericsson.com>
  13 *
  14 * This program is free software; you can redistribute it and/or modify
  15 * it under the terms of the GNU General Public License version 2 as
  16 * published by the Free Software Foundation.
  17 */
  18
  19#include <common.h>
  20#include <asm/io.h>
  21
  22#include <asm/arch/db8500_gpio.h>
  23#include <asm/arch/db8500_pincfg.h>
  24#include <linux/compiler.h>
  25
  26#define IO_ADDR(x) (void *) (x)
  27
  28/*
  29 * The GPIO module in the db8500 Systems-on-Chip is an
  30 * AMBA device, managing 32 pins and alternate functions. The logic block
  31 * is currently only used in the db8500.
  32 */
  33
  34#define GPIO_TOTAL_PINS         268
  35#define GPIO_PINS_PER_BLOCK     32
  36#define GPIO_BLOCKS_COUNT       (GPIO_TOTAL_PINS/GPIO_PINS_PER_BLOCK + 1)
  37#define GPIO_BLOCK(pin)         (((pin + GPIO_PINS_PER_BLOCK) >> 5) - 1)
  38#define GPIO_PIN_WITHIN_BLOCK(pin)      ((pin)%(GPIO_PINS_PER_BLOCK))
  39
  40/* Register in the logic block */
  41#define DB8500_GPIO_DAT         0x00
  42#define DB8500_GPIO_DATS        0x04
  43#define DB8500_GPIO_DATC        0x08
  44#define DB8500_GPIO_PDIS        0x0c
  45#define DB8500_GPIO_DIR         0x10
  46#define DB8500_GPIO_DIRS        0x14
  47#define DB8500_GPIO_DIRC        0x18
  48#define DB8500_GPIO_SLPC        0x1c
  49#define DB8500_GPIO_AFSLA       0x20
  50#define DB8500_GPIO_AFSLB       0x24
  51
  52#define DB8500_GPIO_RIMSC       0x40
  53#define DB8500_GPIO_FIMSC       0x44
  54#define DB8500_GPIO_IS          0x48
  55#define DB8500_GPIO_IC          0x4c
  56#define DB8500_GPIO_RWIMSC      0x50
  57#define DB8500_GPIO_FWIMSC      0x54
  58#define DB8500_GPIO_WKS         0x58
  59
  60static void __iomem *get_gpio_addr(unsigned gpio)
  61{
  62        /* Our list of GPIO chips */
  63        static void __iomem *gpio_addrs[GPIO_BLOCKS_COUNT] = {
  64                IO_ADDR(CFG_GPIO_0_BASE),
  65                IO_ADDR(CFG_GPIO_1_BASE),
  66                IO_ADDR(CFG_GPIO_2_BASE),
  67                IO_ADDR(CFG_GPIO_3_BASE),
  68                IO_ADDR(CFG_GPIO_4_BASE),
  69                IO_ADDR(CFG_GPIO_5_BASE),
  70                IO_ADDR(CFG_GPIO_6_BASE),
  71                IO_ADDR(CFG_GPIO_7_BASE),
  72                IO_ADDR(CFG_GPIO_8_BASE)
  73        };
  74
  75        return gpio_addrs[GPIO_BLOCK(gpio)];
  76}
  77
  78static unsigned get_gpio_offset(unsigned gpio)
  79{
  80        return GPIO_PIN_WITHIN_BLOCK(gpio);
  81}
  82
  83/* Can only be called from config_pin. Don't configure alt-mode directly */
  84static void gpio_set_mode(unsigned gpio, enum db8500_gpio_alt mode)
  85{
  86        void __iomem *addr = get_gpio_addr(gpio);
  87        unsigned offset = get_gpio_offset(gpio);
  88        u32 bit = 1 << offset;
  89        u32 afunc, bfunc;
  90
  91        afunc = readl(addr + DB8500_GPIO_AFSLA) & ~bit;
  92        bfunc = readl(addr + DB8500_GPIO_AFSLB) & ~bit;
  93        if (mode & DB8500_GPIO_ALT_A)
  94                afunc |= bit;
  95        if (mode & DB8500_GPIO_ALT_B)
  96                bfunc |= bit;
  97        writel(afunc, addr + DB8500_GPIO_AFSLA);
  98        writel(bfunc, addr + DB8500_GPIO_AFSLB);
  99}
 100
 101/**
 102 * db8500_gpio_set_pull() - enable/disable pull up/down on a gpio
 103 * @gpio: pin number
 104 * @pull: one of DB8500_GPIO_PULL_DOWN, DB8500_GPIO_PULL_UP,
 105 *  and DB8500_GPIO_PULL_NONE
 106 *
 107 * Enables/disables pull up/down on a specified pin.  This only takes effect if
 108 * the pin is configured as an input (either explicitly or by the alternate
 109 * function).
 110 *
 111 * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
 112 * configured as an input.  Otherwise, due to the way the controller registers
 113 * work, this function will change the value output on the pin.
 114 */
 115void db8500_gpio_set_pull(unsigned gpio, enum db8500_gpio_pull pull)
 116{
 117        void __iomem *addr = get_gpio_addr(gpio);
 118        unsigned offset = get_gpio_offset(gpio);
 119        u32 bit = 1 << offset;
 120        u32 pdis;
 121
 122        pdis = readl(addr + DB8500_GPIO_PDIS);
 123        if (pull == DB8500_GPIO_PULL_NONE)
 124                pdis |= bit;
 125        else
 126                pdis &= ~bit;
 127        writel(pdis, addr + DB8500_GPIO_PDIS);
 128
 129        if (pull == DB8500_GPIO_PULL_UP)
 130                writel(bit, addr + DB8500_GPIO_DATS);
 131        else if (pull == DB8500_GPIO_PULL_DOWN)
 132                writel(bit, addr + DB8500_GPIO_DATC);
 133}
 134
 135void db8500_gpio_make_input(unsigned gpio)
 136{
 137        void __iomem *addr = get_gpio_addr(gpio);
 138        unsigned offset = get_gpio_offset(gpio);
 139
 140        writel(1 << offset, addr + DB8500_GPIO_DIRC);
 141}
 142
 143int db8500_gpio_get_input(unsigned gpio)
 144{
 145        void __iomem *addr = get_gpio_addr(gpio);
 146        unsigned offset = get_gpio_offset(gpio);
 147        u32 bit = 1 << offset;
 148
 149        printf("db8500_gpio_get_input gpio=%u addr=%p offset=%u bit=%#x\n",
 150                gpio, addr, offset, bit);
 151
 152        return (readl(addr + DB8500_GPIO_DAT) & bit) != 0;
 153}
 154
 155void db8500_gpio_make_output(unsigned gpio, int val)
 156{
 157        void __iomem *addr = get_gpio_addr(gpio);
 158        unsigned offset = get_gpio_offset(gpio);
 159
 160        writel(1 << offset, addr + DB8500_GPIO_DIRS);
 161        db8500_gpio_set_output(gpio, val);
 162}
 163
 164void db8500_gpio_set_output(unsigned gpio, int val)
 165{
 166        void __iomem *addr = get_gpio_addr(gpio);
 167        unsigned offset = get_gpio_offset(gpio);
 168
 169        if (val)
 170                writel(1 << offset, addr + DB8500_GPIO_DATS);
 171        else
 172                writel(1 << offset, addr + DB8500_GPIO_DATC);
 173}
 174
 175/**
 176 * config_pin - configure a pin's mux attributes
 177 * @cfg: pin confguration
 178 *
 179 * Configures a pin's mode (alternate function or GPIO), its pull up status,
 180 * and its sleep mode based on the specified configuration.  The @cfg is
 181 * usually one of the SoC specific macros defined in mach/<soc>-pins.h.  These
 182 * are constructed using, and can be further enhanced with, the macros in
 183 * plat/pincfg.h.
 184 *
 185 * If a pin's mode is set to GPIO, it is configured as an input to avoid
 186 * side-effects.  The gpio can be manipulated later using standard GPIO API
 187 * calls.
 188 */
 189static void config_pin(unsigned long cfg)
 190{
 191        int pin = PIN_NUM(cfg);
 192        int pull = PIN_PULL(cfg);
 193        int af = PIN_ALT(cfg);
 194        int output = PIN_DIR(cfg);
 195        int val = PIN_VAL(cfg);
 196
 197        if (output)
 198                db8500_gpio_make_output(pin, val);
 199        else {
 200                db8500_gpio_make_input(pin);
 201                db8500_gpio_set_pull(pin, pull);
 202        }
 203
 204        gpio_set_mode(pin, af);
 205}
 206
 207/**
 208 * db8500_config_pins - configure several pins at once
 209 * @cfgs: array of pin configurations
 210 * @num: number of elments in the array
 211 *
 212 * Configures several pins using config_pin(). Refer to that function for
 213 * further information.
 214 */
 215void db8500_gpio_config_pins(unsigned long *cfgs, size_t num)
 216{
 217        size_t i;
 218
 219        for (i = 0; i < num; i++)
 220                config_pin(cfgs[i]);
 221}
 222