summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJoakim Axelsson <joakim.axelsson@stericsson.com>2010-10-20 14:11:49 +0200
committerMichael BRANDT <michael.brandt@stericsson.com>2010-12-08 16:20:27 +0100
commit307a253778d0918a8e0f10c2ea9a350450e37677 (patch)
tree4f41a9000a90c1b48e3778866abddb3db6eb8efa /drivers
parentc6b4e8c0340357c795f5898cf5e4141e845a2801 (diff)
db8500: New GPIO driver and config, from Linux kernel
Copied the GPIO configurator written for the Linux kernel. The Nomadik db8500 GPIO driver. Purpose is to be able to just cut-n-paste the GPIO config from Linux to U-boot. Also at the same time remove the obsolete and old gpio_alt_funcenable/disable methods. Now all is configured using a table in u8500.c. Now drivers doesn't have to worry about setting up the GPIO pins. Actually no driver today uses GPIO pins directly, only via hardware blocks within db8500. Functions are still added to be able to interact directly with a GPIO pin. This also cleaned up a lot of driver by not having to bit manipulate GPIO registers them self. The new driver is called db8500_gpio and placed in driver/gpio/. Functions are in include/db8500_gpio.h: void db8500_gpio_set_pull(unsigned gpio, enum db8500_gpio_pull pull); void db8500_gpio_make_input(unsigned gpio); int db8500_gpio_get_input(unsigned gpio); void db8500_gpio_make_output(unsigned gpio, int val); void db8500_gpio_set_output(unsigned gpio, int val); And for the configurator in include/db8500_pincfg.h: void db8500_gpio_config_pins(pin_cfg_t *cfgs, size_t num); All in all the final binary size has decreased. This is only done for db8500 nomadik GPIO. The code for gpio expanders has not been touched. All references to Nomadik has been removed in this driver. Only db8500 is left. ST-Ericsson ID: None Signed-off-by: Joakim Axelsson <joakim.axelsson@stericsson.com> Change-Id: I90aa1d46c813ffb5a777c3492b5751f5054f71cf Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/9904 Reviewed-by: QATOOLS Reviewed-by: Michael BRANDT <michael.brandt@stericsson.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/db8500_gpio.c226
-rw-r--r--drivers/spi/u8500_spi.c76
-rwxr-xr-xdrivers/usb/gadget/u8500_udc.c3
4 files changed, 229 insertions, 77 deletions
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index fc3ee5ea9..64f0bd718 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -25,6 +25,7 @@ include $(TOPDIR)/config.mk
LIB := $(obj)libgpio.a
+COBJS-$(CONFIG_DB8500_GPIO) += db8500_gpio.o
COBJS-$(CONFIG_KIRKWOOD_GPIO) += kw_gpio.o
COBJS-$(CONFIG_MX31_GPIO) += mx31_gpio.o
COBJS-$(CONFIG_PCA953X) += pca953x.o
diff --git a/drivers/gpio/db8500_gpio.c b/drivers/gpio/db8500_gpio.c
new file mode 100644
index 000000000..1ed4ba15d
--- /dev/null
+++ b/drivers/gpio/db8500_gpio.c
@@ -0,0 +1,226 @@
+/*
+ * 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 <db8500_gpio.h>
+#include <db8500_pincfg.h>
+
+/*
+ * Macros to work with IO space
+ * Not actually used?
+ */
+#define __iomem
+#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(pin_cfg_t 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(pin_cfg_t *cfgs, size_t num)
+{
+ size_t i;
+
+ for (i = 0; i < num; i++)
+ config_pin(cfgs[i]);
+}
+
diff --git a/drivers/spi/u8500_spi.c b/drivers/spi/u8500_spi.c
index 3b1ae6a5e..a5f4422ce 100644
--- a/drivers/spi/u8500_spi.c
+++ b/drivers/spi/u8500_spi.c
@@ -13,7 +13,6 @@
#include <asm/io.h>
#include <asm/arch/clock.h>
#include <asm/arch/hardware.h>
-#include <asm/arch/gpio.h>
#include <spi.h>
@@ -357,9 +356,6 @@ int spi_claim_bus(struct spi_slave *slave)
{
struct stm_spi_slave *sss = to_stm_spi_slave(slave);
int ret = 0;
- gpio_config pin_config;
- gpio_pin clk_pin, frm_pin, txd_pin, rxd_pin;
- gpio_alt_function altfunc;
pr_dbg("slave 0x%p", slave);
@@ -372,31 +368,16 @@ int spi_claim_bus(struct spi_slave *slave)
switch (sss->slave.bus) {
#if defined(SPI_0_BASE) && defined(CONFIG_U8500)
case 0:
- altfunc = GPIO_ALT_SPI_0;
- clk_pin = GPIO_PIN_220;
- frm_pin = GPIO_PIN_223;
- txd_pin = GPIO_PIN_224;
- rxd_pin = GPIO_PIN_225;
u8500_clock_enable(2, 8, -1);
break;
#endif
#if defined(SPI_1_BASE) && defined(CONFIG_U8500)
case 1:
- altfunc = GPIO_ALT_SPI_1;
- clk_pin = GPIO_PIN_209;
- frm_pin = GPIO_PIN_212;
- txd_pin = GPIO_PIN_213;
- rxd_pin = GPIO_PIN_214;
u8500_clock_enable(2, 2, -1);
break;
#endif
#if defined(SPI_2_BASE) && defined(CONFIG_U8500)
case 2:
- altfunc = GPIO_ALT_SPI_2;
- clk_pin = GPIO_PIN_217;
- frm_pin = GPIO_PIN_216;
- txd_pin = GPIO_PIN_215;
- rxd_pin = GPIO_PIN_218;
u8500_clock_enable(2, 1, -1);
/*
@@ -412,11 +393,6 @@ int spi_claim_bus(struct spi_slave *slave)
#endif
#if defined(SPI_3_BASE) && defined(CONFIG_U8500)
case 3:
- altfunc = GPIO_ALT_SPI_3;
- clk_pin = GPIO_PIN_29;
- frm_pin = GPIO_PIN_31;
- txd_pin = GPIO_PIN_32;
- rxd_pin = GPIO_PIN_30;
u8500_clock_enable(1, 7, -1);
break;
#endif
@@ -447,57 +423,9 @@ int spi_claim_bus(struct spi_slave *slave)
/*
- * 3. Program the GPIO on which SPI port signals are attached to
- * deliver the SPI signals by setting bits alternate function
- * enable GPIO_AFSLAx = 1b in GPIO register.
- *
- * First the GPIO's are configured in software mode so
- * the pull-up/pull-down configuration is correctly applied.
- * After that pins are set to the correct alternate mode.
+ * 3. Program the GPIO on which SPI port signals are attached to.
+ * This should already be done by the Board GPIO setup
*/
- pin_config.dev_name = "SPI_CLK";
- pin_config.direction = GPIO_DIR_OUTPUT;
- pin_config.mode = GPIO_MODE_SOFTWARE;
- pin_config.trig = GPIO_TRIG_DISABLE;
- ret = gpio_setpinconfig(clk_pin, &pin_config);
- if (ret != 0) {
- pr_err("Error %i when configuring '%s' (pin %i) for '%s'",
- ret, pin_config.dev_name, clk_pin, sss->dev_name);
- return ret;
- }
-
- pin_config.dev_name = "SPI_FRM";
- ret = gpio_setpinconfig(frm_pin, &pin_config);
- if (ret != 0) {
- pr_err("Error %i when configuring '%s' (pin %i) for '%s'",
- ret, pin_config.dev_name, frm_pin, sss->dev_name);
- return ret;
- }
-
- pin_config.dev_name = "SPI_TXD";
- ret = gpio_setpinconfig(txd_pin, &pin_config);
- if (ret != 0) {
- pr_err("Error %i when configuring '%s' (pin %i) for '%s'",
- ret, pin_config.dev_name, txd_pin, sss->dev_name);
- return ret;
- }
-
- pin_config.dev_name = "SPI_RXD";
- pin_config.direction = GPIO_DIR_INPUT;
- ret = gpio_setpinconfig(rxd_pin, &pin_config);
- if (ret != 0) {
- pr_err("Error %i when configuring '%s' (pin %i) for '%s'",
- ret, pin_config.dev_name, rxd_pin, sss->dev_name);
- return ret;
- }
-
- ret = gpio_altfuncenable(altfunc, sss->dev_name);
- if (ret != 0) {
- pr_err("Error %i when configuring '%s' to %i",
- ret, sss->dev_name, altfunc);
- return ret;
- }
-
/*
* 4. Program the SPI clock prescale register, SPI_CPSR,
diff --git a/drivers/usb/gadget/u8500_udc.c b/drivers/usb/gadget/u8500_udc.c
index 109e11dda..92f1b57c8 100755
--- a/drivers/usb/gadget/u8500_udc.c
+++ b/drivers/usb/gadget/u8500_udc.c
@@ -21,7 +21,6 @@
#include <common.h>
#include "u8500_udc.h"
-#include <asm/arch/gpio.h>
static volatile struct mg_dev_register *pRegs = 0;
@@ -32,8 +31,6 @@ int udc_musb_platform_init(void)
u8 soft_reset;
u16 temp;
pRegs = (volatile struct mg_dev_register *) CONFIG_USB_BASE;
-
- gpio_altfuncenable(GPIO_ALT_USB_OTG, "USB-OTG");
top = pRegs->OTG_TOPCTRL;
pRegs->OTG_TOPCTRL = (top | MODE_ULPI);