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/io.h> 19 #include <asm/gpio.h> 20 #include <dm/device-internal.h> 21 #ifdef CONFIG_AXP209_POWER 22 #include <axp209.h> 23 #endif 24 25 DECLARE_GLOBAL_DATA_PTR; 26 27 #define SUNXI_GPIOS_PER_BANK SUNXI_GPIO_A_NR 28 29 struct sunxi_gpio_platdata { 30 struct sunxi_gpio *regs; 31 const char *bank_name; /* Name of bank, e.g. "B" */ 32 int gpio_count; 33 }; 34 35 #ifndef CONFIG_DM_GPIO 36 static int sunxi_gpio_output(u32 pin, u32 val) 37 { 38 u32 dat; 39 u32 bank = GPIO_BANK(pin); 40 u32 num = GPIO_NUM(pin); 41 struct sunxi_gpio *pio = BANK_TO_GPIO(bank); 42 43 dat = readl(&pio->dat); 44 if (val) 45 dat |= 0x1 << num; 46 else 47 dat &= ~(0x1 << num); 48 49 writel(dat, &pio->dat); 50 51 return 0; 52 } 53 54 static int sunxi_gpio_input(u32 pin) 55 { 56 u32 dat; 57 u32 bank = GPIO_BANK(pin); 58 u32 num = GPIO_NUM(pin); 59 struct sunxi_gpio *pio = BANK_TO_GPIO(bank); 60 61 dat = readl(&pio->dat); 62 dat >>= num; 63 64 return dat & 0x1; 65 } 66 67 int gpio_request(unsigned gpio, const char *label) 68 { 69 return 0; 70 } 71 72 int gpio_free(unsigned gpio) 73 { 74 return 0; 75 } 76 77 int gpio_direction_input(unsigned gpio) 78 { 79 #ifdef AXP_GPIO 80 if (gpio >= SUNXI_GPIO_AXP0_START) 81 return axp_gpio_direction_input(gpio - SUNXI_GPIO_AXP0_START); 82 #endif 83 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_INPUT); 84 85 return 0; 86 } 87 88 int gpio_direction_output(unsigned gpio, int value) 89 { 90 #ifdef AXP_GPIO 91 if (gpio >= SUNXI_GPIO_AXP0_START) 92 return axp_gpio_direction_output(gpio - SUNXI_GPIO_AXP0_START, 93 value); 94 #endif 95 sunxi_gpio_set_cfgpin(gpio, SUNXI_GPIO_OUTPUT); 96 97 return sunxi_gpio_output(gpio, value); 98 } 99 100 int gpio_get_value(unsigned gpio) 101 { 102 #ifdef AXP_GPIO 103 if (gpio >= SUNXI_GPIO_AXP0_START) 104 return axp_gpio_get_value(gpio - SUNXI_GPIO_AXP0_START); 105 #endif 106 return sunxi_gpio_input(gpio); 107 } 108 109 int gpio_set_value(unsigned gpio, int value) 110 { 111 #ifdef AXP_GPIO 112 if (gpio >= SUNXI_GPIO_AXP0_START) 113 return axp_gpio_set_value(gpio - SUNXI_GPIO_AXP0_START, value); 114 #endif 115 return sunxi_gpio_output(gpio, value); 116 } 117 118 int sunxi_name_to_gpio(const char *name) 119 { 120 int group = 0; 121 int groupsize = 9 * 32; 122 long pin; 123 char *eptr; 124 125 #ifdef AXP_GPIO 126 if (strncasecmp(name, "AXP0-", 5) == 0) { 127 name += 5; 128 pin = simple_strtol(name, &eptr, 10); 129 if (!*name || *eptr) 130 return -1; 131 return SUNXI_GPIO_AXP0_START + pin; 132 } 133 #endif 134 if (*name == 'P' || *name == 'p') 135 name++; 136 if (*name >= 'A') { 137 group = *name - (*name > 'a' ? 'a' : 'A'); 138 groupsize = 32; 139 name++; 140 } 141 142 pin = simple_strtol(name, &eptr, 10); 143 if (!*name || *eptr) 144 return -1; 145 if (pin < 0 || pin > groupsize || group >= 9) 146 return -1; 147 return group * 32 + pin; 148 } 149 #endif 150 151 #ifdef CONFIG_DM_GPIO 152 static int sunxi_gpio_direction_input(struct udevice *dev, unsigned offset) 153 { 154 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 155 156 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_INPUT); 157 158 return 0; 159 } 160 161 static int sunxi_gpio_direction_output(struct udevice *dev, unsigned offset, 162 int value) 163 { 164 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 165 u32 num = GPIO_NUM(offset); 166 167 sunxi_gpio_set_cfgbank(plat->regs, offset, SUNXI_GPIO_OUTPUT); 168 clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0); 169 170 return 0; 171 } 172 173 static int sunxi_gpio_get_value(struct udevice *dev, unsigned offset) 174 { 175 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 176 u32 num = GPIO_NUM(offset); 177 unsigned dat; 178 179 dat = readl(&plat->regs->dat); 180 dat >>= num; 181 182 return dat & 0x1; 183 } 184 185 static int sunxi_gpio_set_value(struct udevice *dev, unsigned offset, 186 int value) 187 { 188 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 189 u32 num = GPIO_NUM(offset); 190 191 clrsetbits_le32(&plat->regs->dat, 1 << num, value ? (1 << num) : 0); 192 return 0; 193 } 194 195 static int sunxi_gpio_get_function(struct udevice *dev, unsigned offset) 196 { 197 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 198 int func; 199 200 func = sunxi_gpio_get_cfgbank(plat->regs, offset); 201 if (func == SUNXI_GPIO_OUTPUT) 202 return GPIOF_OUTPUT; 203 else if (func == SUNXI_GPIO_INPUT) 204 return GPIOF_INPUT; 205 else 206 return GPIOF_FUNC; 207 } 208 209 static const struct dm_gpio_ops gpio_sunxi_ops = { 210 .direction_input = sunxi_gpio_direction_input, 211 .direction_output = sunxi_gpio_direction_output, 212 .get_value = sunxi_gpio_get_value, 213 .set_value = sunxi_gpio_set_value, 214 .get_function = sunxi_gpio_get_function, 215 }; 216 217 /** 218 * Returns the name of a GPIO bank 219 * 220 * GPIO banks are named A, B, C, ... 221 * 222 * @bank: Bank number (0, 1..n-1) 223 * @return allocated string containing the name 224 */ 225 static char *gpio_bank_name(int bank) 226 { 227 char *name; 228 229 name = malloc(2); 230 if (name) { 231 name[0] = 'A' + bank; 232 name[1] = '\0'; 233 } 234 235 return name; 236 } 237 238 static int gpio_sunxi_probe(struct udevice *dev) 239 { 240 struct sunxi_gpio_platdata *plat = dev_get_platdata(dev); 241 struct gpio_dev_priv *uc_priv = dev->uclass_priv; 242 243 /* Tell the uclass how many GPIOs we have */ 244 if (plat) { 245 uc_priv->gpio_count = plat->gpio_count; 246 uc_priv->bank_name = plat->bank_name; 247 } 248 249 return 0; 250 } 251 /** 252 * We have a top-level GPIO device with no actual GPIOs. It has a child 253 * device for each Sunxi bank. 254 */ 255 static int gpio_sunxi_bind(struct udevice *parent) 256 { 257 struct sunxi_gpio_platdata *plat = parent->platdata; 258 struct sunxi_gpio_reg *ctlr; 259 int bank; 260 int ret; 261 262 /* If this is a child device, there is nothing to do here */ 263 if (plat) 264 return 0; 265 266 ctlr = (struct sunxi_gpio_reg *)fdtdec_get_addr(gd->fdt_blob, 267 parent->of_offset, "reg"); 268 for (bank = 0; bank < SUNXI_GPIO_BANKS; bank++) { 269 struct sunxi_gpio_platdata *plat; 270 struct udevice *dev; 271 272 plat = calloc(1, sizeof(*plat)); 273 if (!plat) 274 return -ENOMEM; 275 plat->regs = &ctlr->gpio_bank[bank]; 276 plat->bank_name = gpio_bank_name(bank); 277 plat->gpio_count = SUNXI_GPIOS_PER_BANK; 278 279 ret = device_bind(parent, parent->driver, 280 plat->bank_name, plat, -1, &dev); 281 if (ret) 282 return ret; 283 dev->of_offset = parent->of_offset; 284 } 285 286 return 0; 287 } 288 289 static const struct udevice_id sunxi_gpio_ids[] = { 290 { .compatible = "allwinner,sun7i-a20-pinctrl" }, 291 { } 292 }; 293 294 U_BOOT_DRIVER(gpio_sunxi) = { 295 .name = "gpio_sunxi", 296 .id = UCLASS_GPIO, 297 .ops = &gpio_sunxi_ops, 298 .of_match = sunxi_gpio_ids, 299 .bind = gpio_sunxi_bind, 300 .probe = gpio_sunxi_probe, 301 }; 302 #endif 303