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 60 static 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 78 static 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 */ 84 static 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 */ 115 void 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 135 void 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 143 int 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 155 void 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 164 void 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 configuration 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 */ 189 static 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 */ 215 void 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