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