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