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