1 /* 2 * (C) Copyright 2012 Henrik Nordstrom <henrik@henriknordstrom.net> 3 * 4 * Based on earlier arch/arm/cpu/armv7/sunxi/gpio.c: 5 * 6 * (C) Copyright 2007-2011 7 * Allwinner Technology Co., Ltd. <www.allwinnertech.com> 8 * Tom Cubie <tangliang@allwinnertech.com> 9 * 10 * SPDX-License-Identifier: GPL-2.0+ 11 */ 12 13 #include <common.h> 14 #include <dm.h> 15 #include <errno.h> 16 #include <fdtdec.h> 17 #include <malloc.h> 18 #include <asm/arch/gpio.h> 19 #include <asm/io.h> 20 #include <asm/gpio.h> 21 #include <dm/device-internal.h> 22 23 DECLARE_GLOBAL_DATA_PTR; 24 25 #define SUNXI_GPIOS_PER_BANK SUNXI_GPIO_A_NR 26 27 struct sunxi_gpio_platdata { 28 struct sunxi_gpio *regs; 29 const char *bank_name; /* Name of bank, e.g. "B" */ 30 int gpio_count; 31 }; 32 33 #ifndef CONFIG_DM_GPIO 34 static int sunxi_gpio_output(u32 pin, u32 val) 35 { 36 u32 dat; 37 u32 bank = GPIO_BANK(pin); 38 u32 num = GPIO_NUM(pin); 39 struct sunxi_gpio *pio = BANK_TO_GPIO(bank); 40 41 dat = readl(&pio->dat); 42 if (val) 43 dat |= 0x1 << num; 44 else 45 dat &= ~(0x1 << num); 46 47 writel(dat, &pio->dat); 48 49 return 0; 50 } 51 52 static int sunxi_gpio_input(u32 pin) 53 { 54 u32 dat; 55 u32 bank = GPIO_BANK(pin); 56 u32 num = GPIO_NUM(pin); 57 struct sunxi_gpio *pio = BANK_TO_GPIO(bank); 58 59 dat = readl(&pio->dat); 60 dat >>= num; 61 62 return dat & 0x1; 63 } 64 65 int gpio_request(unsigned gpio, const char *label) 66 { 67 return 0; 68 } 69 70 int gpio_free(unsigned gpio) 71 { 72 return 0; 73 } 74 75 int gpio_direction_input(unsigned gpio) 76 { 77 #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO 78 if (gpio >= SUNXI_GPIO_AXP0_START) 79 return axp_gpio_direction_input(NULL, gpio - SUNXI_GPIO_AXP0_START); 80 #endif 81 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT); 82 83 return 0; 84 } 85 86 int gpio_direction_output(unsigned gpio, int value) 87 { 88 #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO 89 if (gpio >= SUNXI_GPIO_AXP0_START) 90 return axp_gpio_direction_output(NULL, gpio - SUNXI_GPIO_AXP0_START, 91 value); 92 #endif 93 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT); 94 95 return sunxi_gpio_output(gpio, value); 96 } 97 98 int gpio_get_value(unsigned gpio) 99 { 100 #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO 101 if (gpio >= SUNXI_GPIO_AXP0_START) 102 return axp_gpio_get_value(NULL, gpio - SUNXI_GPIO_AXP0_START); 103 #endif 104 return sunxi_gpio_input(gpio); 105 } 106 107 int gpio_set_value(unsigned gpio, int value) 108 { 109 #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO 110 if (gpio >= SUNXI_GPIO_AXP0_START) 111 return axp_gpio_set_value(NULL, gpio - SUNXI_GPIO_AXP0_START, value); 112 #endif 113 return sunxi_gpio_output(gpio, value); 114 } 115 116 int sunxi_name_to_gpio(const char *name) 117 { 118 int group = 0; 119 int groupsize = 9 * 32; 120 long pin; 121 char *eptr; 122 123 #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO 124 if (strncasecmp(name, "AXP0-", 5) == 0) { 125 name += 5; 126 if (strcmp(name, "VBUS-DETECT") == 0) 127 return SUNXI_GPIO_AXP0_START + 128 SUNXI_GPIO_AXP0_VBUS_DETECT; 129 if (strcmp(name, "VBUS-ENABLE") == 0) 130 return SUNXI_GPIO_AXP0_START + 131 SUNXI_GPIO_AXP0_VBUS_ENABLE; 132 pin = simple_strtol(name, &eptr, 10); 133 if (!*name || *eptr) 134 return -1; 135 return SUNXI_GPIO_AXP0_START + pin; 136 } 137 #endif 138 if (*name == 'P' || *name == 'p') 139 name++; 140 if (*name >= 'A') { 141 group = *name - (*name > 'a' ? 'a' : 'A'); 142 groupsize = 32; 143 name++; 144 } 145 146 pin = simple_strtol(name, &eptr, 10); 147 if (!*name || *eptr) 148 return -1; 149 if (pin < 0 || pin > groupsize || group >= 9) 150 return -1; 151 return group * 32 + pin; 152 } 153 #endif 154 155 int sunxi_name_to_gpio_bank(const char *name) 156 { 157 int group = 0; 158 159 if (*name == 'P' || *name == 'p') 160 name++; 161 if (*name >= 'A') { 162 group = *name - (*name > 'a' ? 'a' : 'A'); 163 return group; 164 } 165 166 return -1; 167 } 168 169 #ifdef CONFIG_DM_GPIO 170 /* TODO(sjg@chromium.org): Remove this function and use device tree */ 171 int sunxi_name_to_gpio(const char *name) 172 { 173 unsigned int gpio; 174 int ret; 175 #if !defined CONFIG_SPL_BUILD && defined CONFIG_AXP_GPIO 176 char lookup[8]; 177 178 if (strcasecmp(name, "AXP0-VBUS-DETECT") == 0) { 179 sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d", 180 SUNXI_GPIO_AXP0_VBUS_DETECT); 181 name = lookup; 182 } else if (strcasecmp(name, "AXP0-VBUS-ENABLE") == 0) { 183 sprintf(lookup, SUNXI_GPIO_AXP0_PREFIX "%d", 184 SUNXI_GPIO_AXP0_VBUS_ENABLE); 185 name = lookup; 186 } 187 #endif 188 ret = gpio_lookup_name(name, NULL, NULL, &gpio); 189 190 return ret ? ret : gpio; 191 } 192 193 static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset) 194 { 195 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 196 197 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT); 198 199 return 0; 200 } 201 202 static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset, 203 int value) 204 { 205 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 206 u32 num = GPIO_NUM(offset); 207 208 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT); 209 clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0); 210 211 return 0; 212 } 213 214 static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset) 215 { 216 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 217 u32 num = GPIO_NUM(offset); 218 unsigned dat; 219 220 dat = readl(&plat->regs->dat); 221 dat >>= num; 222 223 return dat & 0x1; 224 } 225 226 static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset, 227 int value) 228 { 229 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 230 u32 num = GPIO_NUM(offset); 231 232 clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0); 233 return 0; 234 } 235 236 static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset) 237 { 238 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 239 int func; 240 241 func = sunxi_gpio_get_cfgbank(plat->regs, offset); 242 if (func == SUNXI_GPIO_OUTPUT) 243 return GPIOF_OUTPUT; 244 else if (func == SUNXI_GPIO_INPUT) 245 return GPIOF_INPUT; 246 else 247 return GPIOF_FUNC; 248 } 249 250 static const struct dm_gpio_ops gpio_sunxi_ops = { 251 .direction_input = sunxi_gpio_direction_input, 252 .direction_output = sunxi_gpio_direction_output, 253 .get_value = sunxi_gpio_get_value, 254 .set_value = sunxi_gpio_set_value, 255 .get_function = sunxi_gpio_get_function, 256 }; 257 258 /** 259 * Returns the name of a GPIO bank 260 * 261 * GPIO banks are named A, B, C, ... 262 * 263 * @bank: Bank number (0, 1..n-1) 264 * @return allocated string containing the name 265 */ 266 static char *gpio_bank_name(int bank) 267 { 268 char *name; 269 270 name = malloc(3); 271 if (name) { 272 name[0] = 'P'; 273 name[1] = 'A' + bank; 274 name[2] = '\0'; 275 } 276 277 return name; 278 } 279 280 static int gpio_sunxi_probe(struct udevice *dev) 281 { 282 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 283 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 284 285 /* Tell the uclass how many GPIOs we have */ 286 if (plat) { 287 uc_priv->gpio_count = plat->gpio_count; 288 uc_priv->bank_name = plat->bank_name; 289 } 290 291 return 0; 292 } 293 /** 294 * We have a top-level GPIO device with no actual GPIOs. It has a child 295 * device for each Sunxi bank. 296 */ 297 static int gpio_sunxi_bind(struct udevice *parent) 298 { 299 struct sunxi_gpio_platdata *plat = parent->platdata; 300 struct sunxi_gpio_reg *ctlr; 301 int bank; 302 int ret; 303 304 /* If this is a child device, there is nothing to do here */ 305 if (plat) 306 return 0; 307 308 ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob, 309 parent->of_offset, "reg"); 310 for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) { 311 struct sunxi_gpio_platdata *plat; 312 struct udevice *dev; 313 314 plat = calloc(1, sizeof(*plat)); 315 if (!plat) 316 return -ENOMEM; 317 plat->regs = &ctlr->gpio_bank[bank]; 318 plat->bank_name = gpio_bank_name(bank); 319 plat->gpio_count = SUNXI_GPIOS_PER_BANK; 320 321 ret = device_bind(parent, parent->driver, 322 plat->bank_name, plat, -1, &dev); 323 if (ret) 324 return ret; 325 dev->of_offset = parent->of_offset; 326 } 327 328 return 0; 329 } 330 331 static const struct udevice_id sunxi_gpio_ids[] = { 332 { .compatible = "allwinner,sun4i-a10-pinctrl" }, 333 { .compatible = "allwinner,sun5i-a10s-pinctrl" }, 334 { .compatible = "allwinner,sun5i-a13-pinctrl" }, 335 { .compatible = "allwinner,sun6i-a31-pinctrl" }, 336 { .compatible = "allwinner,sun6i-a31s-pinctrl" }, 337 { .compatible = "allwinner,sun7i-a20-pinctrl" }, 338 { .compatible = "allwinner,sun8i-a23-pinctrl" }, 339 { .compatible = "allwinner,sun9i-a80-pinctrl" }, 340 { } 341 }; 342 343 U_BOOT_DRIVER(gpio_sunxi) = { 344 .name = "gpio_sunxi", 345 .id = UCLASS_GPIO, 346 .ops = &gpio_sunxi_ops, 347 .of_match = sunxi_gpio_ids, 348 .bind = gpio_sunxi_bind, 349 .probe = gpio_sunxi_probe, 350 }; 351 #endif 352