1/* linux/arch/arm/plat-s3c/gpio-config.c 2 * 3 * Copyright 2008 Openmoko, Inc. 4 * Copyright 2008-2010 Simtec Electronics 5 * Ben Dooks <ben@simtec.co.uk> 6 * http://armlinux.simtec.co.uk/ 7 * 8 * S3C series GPIO configuration core 9 * 10 * This program is free software; you can redistribute it and/or modify 11 * it under the terms of the GNU General Public License version 2 as 12 * published by the Free Software Foundation. 13*/ 14 15#include <linux/kernel.h> 16#include <linux/module.h> 17#include <linux/gpio.h> 18#include <linux/io.h> 19 20#include <plat/gpio-core.h> 21#include <plat/gpio-cfg.h> 22#include <plat/gpio-cfg-helpers.h> 23 24int s3c_gpio_cfgpin(unsigned int pin, unsigned int config) 25{ 26 struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); 27 unsigned long flags; 28 int offset; 29 int ret; 30 31 if (!chip) 32 return -EINVAL; 33 34 offset = pin - chip->chip.base; 35 36 s3c_gpio_lock(chip, flags); 37 ret = s3c_gpio_do_setcfg(chip, offset, config); 38 s3c_gpio_unlock(chip, flags); 39 40 return ret; 41} 42EXPORT_SYMBOL(s3c_gpio_cfgpin); 43 44unsigned s3c_gpio_getcfg(unsigned int pin) 45{ 46 struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); 47 unsigned long flags; 48 unsigned ret = 0; 49 int offset; 50 51 if (chip) { 52 offset = pin - chip->chip.base; 53 54 s3c_gpio_lock(chip, flags); 55 ret = s3c_gpio_do_getcfg(chip, offset); 56 s3c_gpio_unlock(chip, flags); 57 } 58 59 return ret; 60} 61EXPORT_SYMBOL(s3c_gpio_getcfg); 62 63 64int s3c_gpio_setpull(unsigned int pin, s3c_gpio_pull_t pull) 65{ 66 struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); 67 unsigned long flags; 68 int offset, ret; 69 70 if (!chip) 71 return -EINVAL; 72 73 offset = pin - chip->chip.base; 74 75 s3c_gpio_lock(chip, flags); 76 ret = s3c_gpio_do_setpull(chip, offset, pull); 77 s3c_gpio_unlock(chip, flags); 78 79 return ret; 80} 81EXPORT_SYMBOL(s3c_gpio_setpull); 82 83#ifdef CONFIG_S3C_GPIO_CFG_S3C24XX 84int s3c_gpio_setcfg_s3c24xx_a(struct s3c_gpio_chip *chip, 85 unsigned int off, unsigned int cfg) 86{ 87 void __iomem *reg = chip->base; 88 unsigned int shift = off; 89 u32 con; 90 91 if (s3c_gpio_is_cfg_special(cfg)) { 92 cfg &= 0xf; 93 94 /* Map output to 0, and SFN2 to 1 */ 95 cfg -= 1; 96 if (cfg > 1) 97 return -EINVAL; 98 99 cfg <<= shift; 100 } 101 102 con = __raw_readl(reg); 103 con &= ~(0x1 << shift); 104 con |= cfg; 105 __raw_writel(con, reg); 106 107 return 0; 108} 109 110unsigned s3c_gpio_getcfg_s3c24xx_a(struct s3c_gpio_chip *chip, 111 unsigned int off) 112{ 113 u32 con; 114 115 con = __raw_readl(chip->base); 116 con >>= off; 117 con &= 1; 118 con++; 119 120 return S3C_GPIO_SFN(con); 121} 122 123int s3c_gpio_setcfg_s3c24xx(struct s3c_gpio_chip *chip, 124 unsigned int off, unsigned int cfg) 125{ 126 void __iomem *reg = chip->base; 127 unsigned int shift = off * 2; 128 u32 con; 129 130 if (s3c_gpio_is_cfg_special(cfg)) { 131 cfg &= 0xf; 132 if (cfg > 3) 133 return -EINVAL; 134 135 cfg <<= shift; 136 } 137 138 con = __raw_readl(reg); 139 con &= ~(0x3 << shift); 140 con |= cfg; 141 __raw_writel(con, reg); 142 143 return 0; 144} 145 146unsigned int s3c_gpio_getcfg_s3c24xx(struct s3c_gpio_chip *chip, 147 unsigned int off) 148{ 149 u32 con; 150 151 con = __raw_readl(chip->base); 152 con >>= off * 2; 153 con &= 3; 154 155 /* this conversion works for IN and OUT as well as special mode */ 156 return S3C_GPIO_SPECIAL(con); 157} 158#endif 159 160#ifdef CONFIG_S3C_GPIO_CFG_S3C64XX 161int s3c_gpio_setcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip, 162 unsigned int off, unsigned int cfg) 163{ 164 void __iomem *reg = chip->base; 165 unsigned int shift = (off & 7) * 4; 166 u32 con; 167 168 if (off < 8 && chip->chip.ngpio > 8) 169 reg -= 4; 170 171 if (s3c_gpio_is_cfg_special(cfg)) { 172 cfg &= 0xf; 173 cfg <<= shift; 174 } 175 176 con = __raw_readl(reg); 177 con &= ~(0xf << shift); 178 con |= cfg; 179 __raw_writel(con, reg); 180 181 return 0; 182} 183 184unsigned s3c_gpio_getcfg_s3c64xx_4bit(struct s3c_gpio_chip *chip, 185 unsigned int off) 186{ 187 void __iomem *reg = chip->base; 188 unsigned int shift = (off & 7) * 4; 189 u32 con; 190 191 if (off < 8 && chip->chip.ngpio > 8) 192 reg -= 4; 193 194 con = __raw_readl(reg); 195 con >>= shift; 196 con &= 0xf; 197 198 /* this conversion works for IN and OUT as well as special mode */ 199 return S3C_GPIO_SPECIAL(con); 200} 201 202#endif /* CONFIG_S3C_GPIO_CFG_S3C64XX */ 203 204#ifdef CONFIG_S3C_GPIO_PULL_UPDOWN 205int s3c_gpio_setpull_updown(struct s3c_gpio_chip *chip, 206 unsigned int off, s3c_gpio_pull_t pull) 207{ 208 void __iomem *reg = chip->base + 0x08; 209 int shift = off * 2; 210 u32 pup; 211 212 pup = __raw_readl(reg); 213 pup &= ~(3 << shift); 214 pup |= pull << shift; 215 __raw_writel(pup, reg); 216 217 return 0; 218} 219 220s3c_gpio_pull_t s3c_gpio_getpull_updown(struct s3c_gpio_chip *chip, 221 unsigned int off) 222{ 223 void __iomem *reg = chip->base + 0x08; 224 int shift = off * 2; 225 u32 pup = __raw_readl(reg); 226 227 pup >>= shift; 228 pup &= 0x3; 229 return (__force s3c_gpio_pull_t)pup; 230} 231#endif 232 233#ifdef CONFIG_S3C_GPIO_PULL_UP 234int s3c_gpio_setpull_1up(struct s3c_gpio_chip *chip, 235 unsigned int off, s3c_gpio_pull_t pull) 236{ 237 void __iomem *reg = chip->base + 0x08; 238 u32 pup = __raw_readl(reg); 239 240 pup = __raw_readl(reg); 241 242 if (pup == S3C_GPIO_PULL_UP) 243 pup &= ~(1 << off); 244 else if (pup == S3C_GPIO_PULL_NONE) 245 pup |= (1 << off); 246 else 247 return -EINVAL; 248 249 __raw_writel(pup, reg); 250 return 0; 251} 252 253s3c_gpio_pull_t s3c_gpio_getpull_1up(struct s3c_gpio_chip *chip, 254 unsigned int off) 255{ 256 void __iomem *reg = chip->base + 0x08; 257 u32 pup = __raw_readl(reg); 258 259 pup &= (1 << off); 260 return pup ? S3C_GPIO_PULL_NONE : S3C_GPIO_PULL_UP; 261} 262#endif /* CONFIG_S3C_GPIO_PULL_UP */ 263 264#ifdef CONFIG_S5P_GPIO_DRVSTR 265s5p_gpio_drvstr_t s5p_gpio_get_drvstr(unsigned int pin) 266{ 267 struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); 268 unsigned int off; 269 void __iomem *reg; 270 int shift; 271 u32 drvstr; 272 273 if (!chip) 274 return -EINVAL; 275 276 off = pin - chip->chip.base; 277 shift = off * 2; 278 reg = chip->base + 0x0C; 279 280 drvstr = __raw_readl(reg); 281 drvstr = drvstr >> shift; 282 drvstr &= 0x3; 283 284 return (__force s5p_gpio_drvstr_t)drvstr; 285} 286EXPORT_SYMBOL(s5p_gpio_get_drvstr); 287 288int s5p_gpio_set_drvstr(unsigned int pin, s5p_gpio_drvstr_t drvstr) 289{ 290 struct s3c_gpio_chip *chip = s3c_gpiolib_getchip(pin); 291 unsigned int off; 292 void __iomem *reg; 293 int shift; 294 u32 tmp; 295 296 if (!chip) 297 return -EINVAL; 298 299 off = pin - chip->chip.base; 300 shift = off * 2; 301 reg = chip->base + 0x0C; 302 303 tmp = __raw_readl(reg); 304 tmp &= ~(0x3 << shift); 305 tmp |= drvstr << shift; 306 307 __raw_writel(tmp, reg); 308 309 return 0; 310} 311EXPORT_SYMBOL(s5p_gpio_set_drvstr); 312#endif /* CONFIG_S5P_GPIO_DRVSTR */ 313