Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / u-boot / drivers / gpio / db8500_gpio.c
diff --git a/qemu/roms/u-boot/drivers/gpio/db8500_gpio.c b/qemu/roms/u-boot/drivers/gpio/db8500_gpio.c
new file mode 100644 (file)
index 0000000..d5cb383
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Code ported from Nomadik GPIO driver in ST-Ericsson Linux kernel code.
+ * The purpose is that GPIO config found in kernel should work by simply
+ * copy-paste it to U-boot.
+ *
+ * Original Linux authors:
+ * Copyright (C) 2008,2009 STMicroelectronics
+ * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it>
+ *   Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com>
+ *
+ * Ported to U-boot by:
+ * Copyright (C) 2010 Joakim Axelsson <joakim.axelsson AT stericsson.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+
+#include <asm/arch/db8500_gpio.h>
+#include <asm/arch/db8500_pincfg.h>
+#include <linux/compiler.h>
+
+#define IO_ADDR(x) (void *) (x)
+
+/*
+ * The GPIO module in the db8500 Systems-on-Chip is an
+ * AMBA device, managing 32 pins and alternate functions. The logic block
+ * is currently only used in the db8500.
+ */
+
+#define GPIO_TOTAL_PINS                268
+#define GPIO_PINS_PER_BLOCK    32
+#define GPIO_BLOCKS_COUNT      (GPIO_TOTAL_PINS/GPIO_PINS_PER_BLOCK + 1)
+#define GPIO_BLOCK(pin)                (((pin + GPIO_PINS_PER_BLOCK) >> 5) - 1)
+#define GPIO_PIN_WITHIN_BLOCK(pin)     ((pin)%(GPIO_PINS_PER_BLOCK))
+
+/* Register in the logic block */
+#define DB8500_GPIO_DAT                0x00
+#define DB8500_GPIO_DATS       0x04
+#define DB8500_GPIO_DATC       0x08
+#define DB8500_GPIO_PDIS       0x0c
+#define DB8500_GPIO_DIR                0x10
+#define DB8500_GPIO_DIRS       0x14
+#define DB8500_GPIO_DIRC       0x18
+#define DB8500_GPIO_SLPC       0x1c
+#define DB8500_GPIO_AFSLA      0x20
+#define DB8500_GPIO_AFSLB      0x24
+
+#define DB8500_GPIO_RIMSC      0x40
+#define DB8500_GPIO_FIMSC      0x44
+#define DB8500_GPIO_IS         0x48
+#define DB8500_GPIO_IC         0x4c
+#define DB8500_GPIO_RWIMSC     0x50
+#define DB8500_GPIO_FWIMSC     0x54
+#define DB8500_GPIO_WKS                0x58
+
+static void __iomem *get_gpio_addr(unsigned gpio)
+{
+       /* Our list of GPIO chips */
+       static void __iomem *gpio_addrs[GPIO_BLOCKS_COUNT] = {
+               IO_ADDR(CFG_GPIO_0_BASE),
+               IO_ADDR(CFG_GPIO_1_BASE),
+               IO_ADDR(CFG_GPIO_2_BASE),
+               IO_ADDR(CFG_GPIO_3_BASE),
+               IO_ADDR(CFG_GPIO_4_BASE),
+               IO_ADDR(CFG_GPIO_5_BASE),
+               IO_ADDR(CFG_GPIO_6_BASE),
+               IO_ADDR(CFG_GPIO_7_BASE),
+               IO_ADDR(CFG_GPIO_8_BASE)
+       };
+
+       return gpio_addrs[GPIO_BLOCK(gpio)];
+}
+
+static unsigned get_gpio_offset(unsigned gpio)
+{
+       return GPIO_PIN_WITHIN_BLOCK(gpio);
+}
+
+/* Can only be called from config_pin. Don't configure alt-mode directly */
+static void gpio_set_mode(unsigned gpio, enum db8500_gpio_alt mode)
+{
+       void __iomem *addr = get_gpio_addr(gpio);
+       unsigned offset = get_gpio_offset(gpio);
+       u32 bit = 1 << offset;
+       u32 afunc, bfunc;
+
+       afunc = readl(addr + DB8500_GPIO_AFSLA) & ~bit;
+       bfunc = readl(addr + DB8500_GPIO_AFSLB) & ~bit;
+       if (mode & DB8500_GPIO_ALT_A)
+               afunc |= bit;
+       if (mode & DB8500_GPIO_ALT_B)
+               bfunc |= bit;
+       writel(afunc, addr + DB8500_GPIO_AFSLA);
+       writel(bfunc, addr + DB8500_GPIO_AFSLB);
+}
+
+/**
+ * db8500_gpio_set_pull() - enable/disable pull up/down on a gpio
+ * @gpio: pin number
+ * @pull: one of DB8500_GPIO_PULL_DOWN, DB8500_GPIO_PULL_UP,
+ *  and DB8500_GPIO_PULL_NONE
+ *
+ * Enables/disables pull up/down on a specified pin.  This only takes effect if
+ * the pin is configured as an input (either explicitly or by the alternate
+ * function).
+ *
+ * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is
+ * configured as an input.  Otherwise, due to the way the controller registers
+ * work, this function will change the value output on the pin.
+ */
+void db8500_gpio_set_pull(unsigned gpio, enum db8500_gpio_pull pull)
+{
+       void __iomem *addr = get_gpio_addr(gpio);
+       unsigned offset = get_gpio_offset(gpio);
+       u32 bit = 1 << offset;
+       u32 pdis;
+
+       pdis = readl(addr + DB8500_GPIO_PDIS);
+       if (pull == DB8500_GPIO_PULL_NONE)
+               pdis |= bit;
+       else
+               pdis &= ~bit;
+       writel(pdis, addr + DB8500_GPIO_PDIS);
+
+       if (pull == DB8500_GPIO_PULL_UP)
+               writel(bit, addr + DB8500_GPIO_DATS);
+       else if (pull == DB8500_GPIO_PULL_DOWN)
+               writel(bit, addr + DB8500_GPIO_DATC);
+}
+
+void db8500_gpio_make_input(unsigned gpio)
+{
+       void __iomem *addr = get_gpio_addr(gpio);
+       unsigned offset = get_gpio_offset(gpio);
+
+       writel(1 << offset, addr + DB8500_GPIO_DIRC);
+}
+
+int db8500_gpio_get_input(unsigned gpio)
+{
+       void __iomem *addr = get_gpio_addr(gpio);
+       unsigned offset = get_gpio_offset(gpio);
+       u32 bit = 1 << offset;
+
+       printf("db8500_gpio_get_input gpio=%u addr=%p offset=%u bit=%#x\n",
+               gpio, addr, offset, bit);
+
+       return (readl(addr + DB8500_GPIO_DAT) & bit) != 0;
+}
+
+void db8500_gpio_make_output(unsigned gpio, int val)
+{
+       void __iomem *addr = get_gpio_addr(gpio);
+       unsigned offset = get_gpio_offset(gpio);
+
+       writel(1 << offset, addr + DB8500_GPIO_DIRS);
+       db8500_gpio_set_output(gpio, val);
+}
+
+void db8500_gpio_set_output(unsigned gpio, int val)
+{
+       void __iomem *addr = get_gpio_addr(gpio);
+       unsigned offset = get_gpio_offset(gpio);
+
+       if (val)
+               writel(1 << offset, addr + DB8500_GPIO_DATS);
+       else
+               writel(1 << offset, addr + DB8500_GPIO_DATC);
+}
+
+/**
+ * config_pin - configure a pin's mux attributes
+ * @cfg: pin confguration
+ *
+ * Configures a pin's mode (alternate function or GPIO), its pull up status,
+ * and its sleep mode based on the specified configuration.  The @cfg is
+ * usually one of the SoC specific macros defined in mach/<soc>-pins.h.  These
+ * are constructed using, and can be further enhanced with, the macros in
+ * plat/pincfg.h.
+ *
+ * If a pin's mode is set to GPIO, it is configured as an input to avoid
+ * side-effects.  The gpio can be manipulated later using standard GPIO API
+ * calls.
+ */
+static void config_pin(unsigned long cfg)
+{
+       int pin = PIN_NUM(cfg);
+       int pull = PIN_PULL(cfg);
+       int af = PIN_ALT(cfg);
+       int output = PIN_DIR(cfg);
+       int val = PIN_VAL(cfg);
+
+       if (output)
+               db8500_gpio_make_output(pin, val);
+       else {
+               db8500_gpio_make_input(pin);
+               db8500_gpio_set_pull(pin, pull);
+       }
+
+       gpio_set_mode(pin, af);
+}
+
+/**
+ * db8500_config_pins - configure several pins at once
+ * @cfgs: array of pin configurations
+ * @num: number of elments in the array
+ *
+ * Configures several pins using config_pin(). Refer to that function for
+ * further information.
+ */
+void db8500_gpio_config_pins(unsigned long *cfgs, size_t num)
+{
+       size_t i;
+
+       for (i = 0; i < num; i++)
+               config_pin(cfgs[i]);
+}