1 /* 2 * Copyright (c) 2009 Wind River Systems, Inc. 3 * Tom Rix <Tom.Rix@windriver.com> 4 * 5 * SPDX-License-Identifier: GPL-2.0 6 * 7 * This work is derived from the linux 2.6.27 kernel source 8 * To fetch, use the kernel repository 9 * git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git 10 * Use the v2.6.27 tag. 11 * 12 * Below is the original's header including its copyright 13 * 14 * linux/arch/arm/plat-omap/gpio.c 15 * 16 * Support functions for OMAP GPIO 17 * 18 * Copyright (C) 2003-2005 Nokia Corporation 19 * Written by Juha Yrjölä <juha.yrjola@nokia.com> 20 */ 21 #include <common.h> 22 #include <dm.h> 23 #include <asm/gpio.h> 24 #include <asm/io.h> 25 #include <asm/errno.h> 26 27 #define OMAP_GPIO_DIR_OUT 0 28 #define OMAP_GPIO_DIR_IN 1 29 30 #ifdef CONFIG_DM_GPIO 31 32 #define GPIO_PER_BANK 32 33 34 struct gpio_bank { 35 /* TODO(sjg@chromium.org): Can we use a struct here? */ 36 void *base; /* address of registers in physical memory */ 37 enum gpio_method method; 38 }; 39 40 #endif 41 42 static inline int get_gpio_index(int gpio) 43 { 44 return gpio & 0x1f; 45 } 46 47 int gpio_is_valid(int gpio) 48 { 49 return (gpio >= 0) && (gpio < OMAP_MAX_GPIO); 50 } 51 52 static void _set_gpio_direction(const struct gpio_bank *bank, int gpio, 53 int is_input) 54 { 55 void *reg = bank->base; 56 u32 l; 57 58 switch (bank->method) { 59 case METHOD_GPIO_24XX: 60 reg += OMAP_GPIO_OE; 61 break; 62 default: 63 return; 64 } 65 l = __raw_readl(reg); 66 if (is_input) 67 l |= 1 << gpio; 68 else 69 l &= ~(1 << gpio); 70 __raw_writel(l, reg); 71 } 72 73 /** 74 * Get the direction of the GPIO by reading the GPIO_OE register 75 * corresponding to the specified bank. 76 */ 77 static int _get_gpio_direction(const struct gpio_bank *bank, int gpio) 78 { 79 void *reg = bank->base; 80 u32 v; 81 82 switch (bank->method) { 83 case METHOD_GPIO_24XX: 84 reg += OMAP_GPIO_OE; 85 break; 86 default: 87 return -1; 88 } 89 90 v = __raw_readl(reg); 91 92 if (v & (1 << gpio)) 93 return OMAP_GPIO_DIR_IN; 94 else 95 return OMAP_GPIO_DIR_OUT; 96 } 97 98 static void _set_gpio_dataout(const struct gpio_bank *bank, int gpio, 99 int enable) 100 { 101 void *reg = bank->base; 102 u32 l = 0; 103 104 switch (bank->method) { 105 case METHOD_GPIO_24XX: 106 if (enable) 107 reg += OMAP_GPIO_SETDATAOUT; 108 else 109 reg += OMAP_GPIO_CLEARDATAOUT; 110 l = 1 << gpio; 111 break; 112 default: 113 printf("omap3-gpio unknown bank method %s %d\n", 114 __FILE__, __LINE__); 115 return; 116 } 117 __raw_writel(l, reg); 118 } 119 120 static int _get_gpio_value(const struct gpio_bank *bank, int gpio) 121 { 122 void *reg = bank->base; 123 int input; 124 125 switch (bank->method) { 126 case METHOD_GPIO_24XX: 127 input = _get_gpio_direction(bank, gpio); 128 switch (input) { 129 case OMAP_GPIO_DIR_IN: 130 reg += OMAP_GPIO_DATAIN; 131 break; 132 case OMAP_GPIO_DIR_OUT: 133 reg += OMAP_GPIO_DATAOUT; 134 break; 135 default: 136 return -1; 137 } 138 break; 139 default: 140 return -1; 141 } 142 143 return (__raw_readl(reg) & (1 << gpio)) != 0; 144 } 145 146 #ifndef CONFIG_DM_GPIO 147 148 static inline const struct gpio_bank *get_gpio_bank(int gpio) 149 { 150 return &omap_gpio_bank[gpio >> 5]; 151 } 152 153 static int check_gpio(int gpio) 154 { 155 if (!gpio_is_valid(gpio)) { 156 printf("ERROR : check_gpio: invalid GPIO %d\n", gpio); 157 return -1; 158 } 159 return 0; 160 } 161 162 /** 163 * Set value of the specified gpio 164 */ 165 int gpio_set_value(unsigned gpio, int value) 166 { 167 const struct gpio_bank *bank; 168 169 if (check_gpio(gpio) < 0) 170 return -1; 171 bank = get_gpio_bank(gpio); 172 _set_gpio_dataout(bank, get_gpio_index(gpio), value); 173 174 return 0; 175 } 176 177 /** 178 * Get value of the specified gpio 179 */ 180 int gpio_get_value(unsigned gpio) 181 { 182 const struct gpio_bank *bank; 183 184 if (check_gpio(gpio) < 0) 185 return -1; 186 bank = get_gpio_bank(gpio); 187 188 return _get_gpio_value(bank, get_gpio_index(gpio)); 189 } 190 191 /** 192 * Set gpio direction as input 193 */ 194 int gpio_direction_input(unsigned gpio) 195 { 196 const struct gpio_bank *bank; 197 198 if (check_gpio(gpio) < 0) 199 return -1; 200 201 bank = get_gpio_bank(gpio); 202 _set_gpio_direction(bank, get_gpio_index(gpio), 1); 203 204 return 0; 205 } 206 207 /** 208 * Set gpio direction as output 209 */ 210 int gpio_direction_output(unsigned gpio, int value) 211 { 212 const struct gpio_bank *bank; 213 214 if (check_gpio(gpio) < 0) 215 return -1; 216 217 bank = get_gpio_bank(gpio); 218 _set_gpio_dataout(bank, get_gpio_index(gpio), value); 219 _set_gpio_direction(bank, get_gpio_index(gpio), 0); 220 221 return 0; 222 } 223 224 /** 225 * Request a gpio before using it. 226 * 227 * NOTE: Argument 'label' is unused. 228 */ 229 int gpio_request(unsigned gpio, const char *label) 230 { 231 if (check_gpio(gpio) < 0) 232 return -1; 233 234 return 0; 235 } 236 237 /** 238 * Reset and free the gpio after using it. 239 */ 240 int gpio_free(unsigned gpio) 241 { 242 return 0; 243 } 244 245 #else /* new driver model interface CONFIG_DM_GPIO */ 246 247 /* set GPIO pin 'gpio' as an input */ 248 static int omap_gpio_direction_input(struct udevice *dev, unsigned offset) 249 { 250 struct gpio_bank *bank = dev_get_priv(dev); 251 252 /* Configure GPIO direction as input. */ 253 _set_gpio_direction(bank, offset, 1); 254 255 return 0; 256 } 257 258 /* set GPIO pin 'gpio' as an output, with polarity 'value' */ 259 static int omap_gpio_direction_output(struct udevice *dev, unsigned offset, 260 int value) 261 { 262 struct gpio_bank *bank = dev_get_priv(dev); 263 264 _set_gpio_dataout(bank, offset, value); 265 _set_gpio_direction(bank, offset, 0); 266 267 return 0; 268 } 269 270 /* read GPIO IN value of pin 'gpio' */ 271 static int omap_gpio_get_value(struct udevice *dev, unsigned offset) 272 { 273 struct gpio_bank *bank = dev_get_priv(dev); 274 275 return _get_gpio_value(bank, offset); 276 } 277 278 /* write GPIO OUT value to pin 'gpio' */ 279 static int omap_gpio_set_value(struct udevice *dev, unsigned offset, 280 int value) 281 { 282 struct gpio_bank *bank = dev_get_priv(dev); 283 284 _set_gpio_dataout(bank, offset, value); 285 286 return 0; 287 } 288 289 static int omap_gpio_get_function(struct udevice *dev, unsigned offset) 290 { 291 struct gpio_bank *bank = dev_get_priv(dev); 292 293 /* GPIOF_FUNC is not implemented yet */ 294 if (_get_gpio_direction(bank->base, offset) == OMAP_GPIO_DIR_OUT) 295 return GPIOF_OUTPUT; 296 else 297 return GPIOF_INPUT; 298 } 299 300 static const struct dm_gpio_ops gpio_omap_ops = { 301 .direction_input = omap_gpio_direction_input, 302 .direction_output = omap_gpio_direction_output, 303 .get_value = omap_gpio_get_value, 304 .set_value = omap_gpio_set_value, 305 .get_function = omap_gpio_get_function, 306 }; 307 308 static int omap_gpio_probe(struct udevice *dev) 309 { 310 struct gpio_bank *bank = dev_get_priv(dev); 311 struct omap_gpio_platdata *plat = dev_get_platdata(dev); 312 struct gpio_dev_priv *uc_priv = dev->uclass_priv; 313 char name[18], *str; 314 315 sprintf(name, "GPIO%d_", plat->bank_index); 316 str = strdup(name); 317 if (!str) 318 return -ENOMEM; 319 uc_priv->bank_name = str; 320 uc_priv->gpio_count = GPIO_PER_BANK; 321 bank->base = (void *)plat->base; 322 bank->method = plat->method; 323 324 return 0; 325 } 326 327 U_BOOT_DRIVER(gpio_omap) = { 328 .name = "gpio_omap", 329 .id = UCLASS_GPIO, 330 .ops = &gpio_omap_ops, 331 .probe = omap_gpio_probe, 332 .priv_auto_alloc_size = sizeof(struct gpio_bank), 333 }; 334 335 #endif /* CONFIG_DM_GPIO */ 336