184dee301SMathieu J. Poirier /* 284dee301SMathieu J. Poirier * Code ported from Nomadik GPIO driver in ST-Ericsson Linux kernel code. 384dee301SMathieu J. Poirier * The purpose is that GPIO config found in kernel should work by simply 4*a187559eSBin Meng * copy-paste it to U-Boot. 584dee301SMathieu J. Poirier * 684dee301SMathieu J. Poirier * Original Linux authors: 784dee301SMathieu J. Poirier * Copyright (C) 2008,2009 STMicroelectronics 884dee301SMathieu J. Poirier * Copyright (C) 2009 Alessandro Rubini <rubini@unipv.it> 984dee301SMathieu J. Poirier * Rewritten based on work by Prafulla WADASKAR <prafulla.wadaskar@st.com> 1084dee301SMathieu J. Poirier * 11*a187559eSBin Meng * Ported to U-Boot by: 1284dee301SMathieu J. Poirier * Copyright (C) 2010 Joakim Axelsson <joakim.axelsson AT stericsson.com> 1384dee301SMathieu J. Poirier * 1484dee301SMathieu J. Poirier * This program is free software; you can redistribute it and/or modify 1584dee301SMathieu J. Poirier * it under the terms of the GNU General Public License version 2 as 1684dee301SMathieu J. Poirier * published by the Free Software Foundation. 1784dee301SMathieu J. Poirier */ 1884dee301SMathieu J. Poirier 1984dee301SMathieu J. Poirier #include <common.h> 2084dee301SMathieu J. Poirier #include <asm/io.h> 2184dee301SMathieu J. Poirier 2284dee301SMathieu J. Poirier #include <asm/arch/db8500_gpio.h> 2384dee301SMathieu J. Poirier #include <asm/arch/db8500_pincfg.h> 2484dee301SMathieu J. Poirier #include <linux/compiler.h> 2584dee301SMathieu J. Poirier 2684dee301SMathieu J. Poirier #define IO_ADDR(x) (void *) (x) 2784dee301SMathieu J. Poirier 2884dee301SMathieu J. Poirier /* 2984dee301SMathieu J. Poirier * The GPIO module in the db8500 Systems-on-Chip is an 3084dee301SMathieu J. Poirier * AMBA device, managing 32 pins and alternate functions. The logic block 3184dee301SMathieu J. Poirier * is currently only used in the db8500. 3284dee301SMathieu J. Poirier */ 3384dee301SMathieu J. Poirier 3484dee301SMathieu J. Poirier #define GPIO_TOTAL_PINS 268 3584dee301SMathieu J. Poirier #define GPIO_PINS_PER_BLOCK 32 3684dee301SMathieu J. Poirier #define GPIO_BLOCKS_COUNT (GPIO_TOTAL_PINS/GPIO_PINS_PER_BLOCK + 1) 3784dee301SMathieu J. Poirier #define GPIO_BLOCK(pin) (((pin + GPIO_PINS_PER_BLOCK) >> 5) - 1) 3884dee301SMathieu J. Poirier #define GPIO_PIN_WITHIN_BLOCK(pin) ((pin)%(GPIO_PINS_PER_BLOCK)) 3984dee301SMathieu J. Poirier 4084dee301SMathieu J. Poirier /* Register in the logic block */ 4184dee301SMathieu J. Poirier #define DB8500_GPIO_DAT 0x00 4284dee301SMathieu J. Poirier #define DB8500_GPIO_DATS 0x04 4384dee301SMathieu J. Poirier #define DB8500_GPIO_DATC 0x08 4484dee301SMathieu J. Poirier #define DB8500_GPIO_PDIS 0x0c 4584dee301SMathieu J. Poirier #define DB8500_GPIO_DIR 0x10 4684dee301SMathieu J. Poirier #define DB8500_GPIO_DIRS 0x14 4784dee301SMathieu J. Poirier #define DB8500_GPIO_DIRC 0x18 4884dee301SMathieu J. Poirier #define DB8500_GPIO_SLPC 0x1c 4984dee301SMathieu J. Poirier #define DB8500_GPIO_AFSLA 0x20 5084dee301SMathieu J. Poirier #define DB8500_GPIO_AFSLB 0x24 5184dee301SMathieu J. Poirier 5284dee301SMathieu J. Poirier #define DB8500_GPIO_RIMSC 0x40 5384dee301SMathieu J. Poirier #define DB8500_GPIO_FIMSC 0x44 5484dee301SMathieu J. Poirier #define DB8500_GPIO_IS 0x48 5584dee301SMathieu J. Poirier #define DB8500_GPIO_IC 0x4c 5684dee301SMathieu J. Poirier #define DB8500_GPIO_RWIMSC 0x50 5784dee301SMathieu J. Poirier #define DB8500_GPIO_FWIMSC 0x54 5884dee301SMathieu J. Poirier #define DB8500_GPIO_WKS 0x58 5984dee301SMathieu J. Poirier 6084dee301SMathieu J. Poirier static void __iomem *get_gpio_addr(unsigned gpio) 6184dee301SMathieu J. Poirier { 6284dee301SMathieu J. Poirier /* Our list of GPIO chips */ 6384dee301SMathieu J. Poirier static void __iomem *gpio_addrs[GPIO_BLOCKS_COUNT] = { 6484dee301SMathieu J. Poirier IO_ADDR(CFG_GPIO_0_BASE), 6584dee301SMathieu J. Poirier IO_ADDR(CFG_GPIO_1_BASE), 6684dee301SMathieu J. Poirier IO_ADDR(CFG_GPIO_2_BASE), 6784dee301SMathieu J. Poirier IO_ADDR(CFG_GPIO_3_BASE), 6884dee301SMathieu J. Poirier IO_ADDR(CFG_GPIO_4_BASE), 6984dee301SMathieu J. Poirier IO_ADDR(CFG_GPIO_5_BASE), 7084dee301SMathieu J. Poirier IO_ADDR(CFG_GPIO_6_BASE), 7184dee301SMathieu J. Poirier IO_ADDR(CFG_GPIO_7_BASE), 7284dee301SMathieu J. Poirier IO_ADDR(CFG_GPIO_8_BASE) 7384dee301SMathieu J. Poirier }; 7484dee301SMathieu J. Poirier 7584dee301SMathieu J. Poirier return gpio_addrs[GPIO_BLOCK(gpio)]; 7684dee301SMathieu J. Poirier } 7784dee301SMathieu J. Poirier 7884dee301SMathieu J. Poirier static unsigned get_gpio_offset(unsigned gpio) 7984dee301SMathieu J. Poirier { 8084dee301SMathieu J. Poirier return GPIO_PIN_WITHIN_BLOCK(gpio); 8184dee301SMathieu J. Poirier } 8284dee301SMathieu J. Poirier 8384dee301SMathieu J. Poirier /* Can only be called from config_pin. Don't configure alt-mode directly */ 8484dee301SMathieu J. Poirier static void gpio_set_mode(unsigned gpio, enum db8500_gpio_alt mode) 8584dee301SMathieu J. Poirier { 8684dee301SMathieu J. Poirier void __iomem *addr = get_gpio_addr(gpio); 8784dee301SMathieu J. Poirier unsigned offset = get_gpio_offset(gpio); 8884dee301SMathieu J. Poirier u32 bit = 1 << offset; 8984dee301SMathieu J. Poirier u32 afunc, bfunc; 9084dee301SMathieu J. Poirier 9184dee301SMathieu J. Poirier afunc = readl(addr + DB8500_GPIO_AFSLA) & ~bit; 9284dee301SMathieu J. Poirier bfunc = readl(addr + DB8500_GPIO_AFSLB) & ~bit; 9384dee301SMathieu J. Poirier if (mode & DB8500_GPIO_ALT_A) 9484dee301SMathieu J. Poirier afunc |= bit; 9584dee301SMathieu J. Poirier if (mode & DB8500_GPIO_ALT_B) 9684dee301SMathieu J. Poirier bfunc |= bit; 9784dee301SMathieu J. Poirier writel(afunc, addr + DB8500_GPIO_AFSLA); 9884dee301SMathieu J. Poirier writel(bfunc, addr + DB8500_GPIO_AFSLB); 9984dee301SMathieu J. Poirier } 10084dee301SMathieu J. Poirier 10184dee301SMathieu J. Poirier /** 10284dee301SMathieu J. Poirier * db8500_gpio_set_pull() - enable/disable pull up/down on a gpio 10384dee301SMathieu J. Poirier * @gpio: pin number 10484dee301SMathieu J. Poirier * @pull: one of DB8500_GPIO_PULL_DOWN, DB8500_GPIO_PULL_UP, 10584dee301SMathieu J. Poirier * and DB8500_GPIO_PULL_NONE 10684dee301SMathieu J. Poirier * 10784dee301SMathieu J. Poirier * Enables/disables pull up/down on a specified pin. This only takes effect if 10884dee301SMathieu J. Poirier * the pin is configured as an input (either explicitly or by the alternate 10984dee301SMathieu J. Poirier * function). 11084dee301SMathieu J. Poirier * 11184dee301SMathieu J. Poirier * NOTE: If enabling the pull up/down, the caller must ensure that the GPIO is 11284dee301SMathieu J. Poirier * configured as an input. Otherwise, due to the way the controller registers 11384dee301SMathieu J. Poirier * work, this function will change the value output on the pin. 11484dee301SMathieu J. Poirier */ 11584dee301SMathieu J. Poirier void db8500_gpio_set_pull(unsigned gpio, enum db8500_gpio_pull pull) 11684dee301SMathieu J. Poirier { 11784dee301SMathieu J. Poirier void __iomem *addr = get_gpio_addr(gpio); 11884dee301SMathieu J. Poirier unsigned offset = get_gpio_offset(gpio); 11984dee301SMathieu J. Poirier u32 bit = 1 << offset; 12084dee301SMathieu J. Poirier u32 pdis; 12184dee301SMathieu J. Poirier 12284dee301SMathieu J. Poirier pdis = readl(addr + DB8500_GPIO_PDIS); 12384dee301SMathieu J. Poirier if (pull == DB8500_GPIO_PULL_NONE) 12484dee301SMathieu J. Poirier pdis |= bit; 12584dee301SMathieu J. Poirier else 12684dee301SMathieu J. Poirier pdis &= ~bit; 12784dee301SMathieu J. Poirier writel(pdis, addr + DB8500_GPIO_PDIS); 12884dee301SMathieu J. Poirier 12984dee301SMathieu J. Poirier if (pull == DB8500_GPIO_PULL_UP) 13084dee301SMathieu J. Poirier writel(bit, addr + DB8500_GPIO_DATS); 13184dee301SMathieu J. Poirier else if (pull == DB8500_GPIO_PULL_DOWN) 13284dee301SMathieu J. Poirier writel(bit, addr + DB8500_GPIO_DATC); 13384dee301SMathieu J. Poirier } 13484dee301SMathieu J. Poirier 13584dee301SMathieu J. Poirier void db8500_gpio_make_input(unsigned gpio) 13684dee301SMathieu J. Poirier { 13784dee301SMathieu J. Poirier void __iomem *addr = get_gpio_addr(gpio); 13884dee301SMathieu J. Poirier unsigned offset = get_gpio_offset(gpio); 13984dee301SMathieu J. Poirier 14084dee301SMathieu J. Poirier writel(1 << offset, addr + DB8500_GPIO_DIRC); 14184dee301SMathieu J. Poirier } 14284dee301SMathieu J. Poirier 14384dee301SMathieu J. Poirier int db8500_gpio_get_input(unsigned gpio) 14484dee301SMathieu J. Poirier { 14584dee301SMathieu J. Poirier void __iomem *addr = get_gpio_addr(gpio); 14684dee301SMathieu J. Poirier unsigned offset = get_gpio_offset(gpio); 14784dee301SMathieu J. Poirier u32 bit = 1 << offset; 14884dee301SMathieu J. Poirier 14984dee301SMathieu J. Poirier printf("db8500_gpio_get_input gpio=%u addr=%p offset=%u bit=%#x\n", 15084dee301SMathieu J. Poirier gpio, addr, offset, bit); 15184dee301SMathieu J. Poirier 15284dee301SMathieu J. Poirier return (readl(addr + DB8500_GPIO_DAT) & bit) != 0; 15384dee301SMathieu J. Poirier } 15484dee301SMathieu J. Poirier 15584dee301SMathieu J. Poirier void db8500_gpio_make_output(unsigned gpio, int val) 15684dee301SMathieu J. Poirier { 15784dee301SMathieu J. Poirier void __iomem *addr = get_gpio_addr(gpio); 15884dee301SMathieu J. Poirier unsigned offset = get_gpio_offset(gpio); 15984dee301SMathieu J. Poirier 16084dee301SMathieu J. Poirier writel(1 << offset, addr + DB8500_GPIO_DIRS); 16184dee301SMathieu J. Poirier db8500_gpio_set_output(gpio, val); 16284dee301SMathieu J. Poirier } 16384dee301SMathieu J. Poirier 16484dee301SMathieu J. Poirier void db8500_gpio_set_output(unsigned gpio, int val) 16584dee301SMathieu J. Poirier { 16684dee301SMathieu J. Poirier void __iomem *addr = get_gpio_addr(gpio); 16784dee301SMathieu J. Poirier unsigned offset = get_gpio_offset(gpio); 16884dee301SMathieu J. Poirier 16984dee301SMathieu J. Poirier if (val) 17084dee301SMathieu J. Poirier writel(1 << offset, addr + DB8500_GPIO_DATS); 17184dee301SMathieu J. Poirier else 17284dee301SMathieu J. Poirier writel(1 << offset, addr + DB8500_GPIO_DATC); 17384dee301SMathieu J. Poirier } 17484dee301SMathieu J. Poirier 17584dee301SMathieu J. Poirier /** 17684dee301SMathieu J. Poirier * config_pin - configure a pin's mux attributes 17784dee301SMathieu J. Poirier * @cfg: pin confguration 17884dee301SMathieu J. Poirier * 17984dee301SMathieu J. Poirier * Configures a pin's mode (alternate function or GPIO), its pull up status, 18084dee301SMathieu J. Poirier * and its sleep mode based on the specified configuration. The @cfg is 18184dee301SMathieu J. Poirier * usually one of the SoC specific macros defined in mach/<soc>-pins.h. These 18284dee301SMathieu J. Poirier * are constructed using, and can be further enhanced with, the macros in 18384dee301SMathieu J. Poirier * plat/pincfg.h. 18484dee301SMathieu J. Poirier * 18584dee301SMathieu J. Poirier * If a pin's mode is set to GPIO, it is configured as an input to avoid 18684dee301SMathieu J. Poirier * side-effects. The gpio can be manipulated later using standard GPIO API 18784dee301SMathieu J. Poirier * calls. 18884dee301SMathieu J. Poirier */ 18984dee301SMathieu J. Poirier static void config_pin(unsigned long cfg) 19084dee301SMathieu J. Poirier { 19184dee301SMathieu J. Poirier int pin = PIN_NUM(cfg); 19284dee301SMathieu J. Poirier int pull = PIN_PULL(cfg); 19384dee301SMathieu J. Poirier int af = PIN_ALT(cfg); 19484dee301SMathieu J. Poirier int output = PIN_DIR(cfg); 19584dee301SMathieu J. Poirier int val = PIN_VAL(cfg); 19684dee301SMathieu J. Poirier 19784dee301SMathieu J. Poirier if (output) 19884dee301SMathieu J. Poirier db8500_gpio_make_output(pin, val); 19984dee301SMathieu J. Poirier else { 20084dee301SMathieu J. Poirier db8500_gpio_make_input(pin); 20184dee301SMathieu J. Poirier db8500_gpio_set_pull(pin, pull); 20284dee301SMathieu J. Poirier } 20384dee301SMathieu J. Poirier 20484dee301SMathieu J. Poirier gpio_set_mode(pin, af); 20584dee301SMathieu J. Poirier } 20684dee301SMathieu J. Poirier 20784dee301SMathieu J. Poirier /** 20884dee301SMathieu J. Poirier * db8500_config_pins - configure several pins at once 20984dee301SMathieu J. Poirier * @cfgs: array of pin configurations 21084dee301SMathieu J. Poirier * @num: number of elments in the array 21184dee301SMathieu J. Poirier * 21284dee301SMathieu J. Poirier * Configures several pins using config_pin(). Refer to that function for 21384dee301SMathieu J. Poirier * further information. 21484dee301SMathieu J. Poirier */ 21584dee301SMathieu J. Poirier void db8500_gpio_config_pins(unsigned long *cfgs, size_t num) 21684dee301SMathieu J. Poirier { 21784dee301SMathieu J. Poirier size_t i; 21884dee301SMathieu J. Poirier 21984dee301SMathieu J. Poirier for (i = 0; i < num; i++) 22084dee301SMathieu J. Poirier config_pin(cfgs[i]); 22184dee301SMathieu J. Poirier } 222