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