Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 | // SPDX-License-Identifier: GPL-2.0+ /* * (C) Copyright 2015 Marek Vasut <marex@denx.de> * * DesignWare APB GPIO driver */ #include <asm/gpio.h> #include <asm/io.h> #include <dm/device.h> #include <dm/device-internal.h> #include <dm/device_compat.h> #include <dm/devres.h> #include <dm/read.h> #include <errno.h> #include <reset.h> #define GPIO_SWPORT_DR(p) (0x00 + (p) * 0xc) #define GPIO_SWPORT_DDR(p) (0x04 + (p) * 0xc) #define GPIO_INTEN 0x30 #define GPIO_INTMASK 0x34 #define GPIO_INTTYPE_LEVEL 0x38 #define GPIO_INT_POLARITY 0x3c #define GPIO_INTSTATUS 0x40 #define GPIO_PORTA_DEBOUNCE 0x48 #define GPIO_PORTA_EOI 0x4c #define GPIO_EXT_PORT(p) (0x50 + (p) * 4) struct gpio_dwapb_priv { struct reset_ctl_bulk resets; }; struct gpio_dwapb_plat { const char *name; int bank; int pins; void __iomem *base; }; static int dwapb_gpio_direction_input(struct udevice *dev, unsigned pin) { struct gpio_dwapb_plat *plat = dev_get_plat(dev); clrbits_le32(plat->base + GPIO_SWPORT_DDR(plat->bank), 1 << pin); return 0; } static int dwapb_gpio_direction_output(struct udevice *dev, unsigned pin, int val) { struct gpio_dwapb_plat *plat = dev_get_plat(dev); setbits_le32(plat->base + GPIO_SWPORT_DDR(plat->bank), 1 << pin); if (val) setbits_le32(plat->base + GPIO_SWPORT_DR(plat->bank), 1 << pin); else clrbits_le32(plat->base + GPIO_SWPORT_DR(plat->bank), 1 << pin); return 0; } static int dwapb_gpio_set_value(struct udevice *dev, unsigned pin, int val) { struct gpio_dwapb_plat *plat = dev_get_plat(dev); if (val) setbits_le32(plat->base + GPIO_SWPORT_DR(plat->bank), 1 << pin); else clrbits_le32(plat->base + GPIO_SWPORT_DR(plat->bank), 1 << pin); return 0; } static int dwapb_gpio_get_function(struct udevice *dev, unsigned offset) { struct gpio_dwapb_plat *plat = dev_get_plat(dev); u32 gpio; gpio = readl(plat->base + GPIO_SWPORT_DDR(plat->bank)); if (gpio & BIT(offset)) return GPIOF_OUTPUT; else return GPIOF_INPUT; } static int dwapb_gpio_get_value(struct udevice *dev, unsigned pin) { struct gpio_dwapb_plat *plat = dev_get_plat(dev); u32 value; if (dwapb_gpio_get_function(dev, pin) == GPIOF_OUTPUT) value = readl(plat->base + GPIO_SWPORT_DR(plat->bank)); else value = readl(plat->base + GPIO_EXT_PORT(plat->bank)); return !!(value & BIT(pin)); } static const struct dm_gpio_ops gpio_dwapb_ops = { .direction_input = dwapb_gpio_direction_input, .direction_output = dwapb_gpio_direction_output, .get_value = dwapb_gpio_get_value, .set_value = dwapb_gpio_set_value, .get_function = dwapb_gpio_get_function, }; static int gpio_dwapb_reset(struct udevice *dev) { int ret; struct gpio_dwapb_priv *priv = dev_get_priv(dev); ret = reset_get_bulk(dev, &priv->resets); if (ret) { /* Return 0 if error due to !CONFIG_DM_RESET and reset * DT property is not present. */ if (ret == -ENOENT || ret == -ENOTSUPP) return 0; dev_warn(dev, "Can't get reset: %d\n", ret); return ret; } ret = reset_deassert_bulk(&priv->resets); if (ret) { reset_release_bulk(&priv->resets); dev_err(dev, "Failed to reset: %d\n", ret); return ret; } return 0; } static int gpio_dwapb_probe(struct udevice *dev) { struct gpio_dev_priv *priv = dev_get_uclass_priv(dev); struct gpio_dwapb_plat *plat = dev_get_plat(dev); if (!plat) { /* Reset on parent device only */ return gpio_dwapb_reset(dev); } priv->gpio_count = plat->pins; priv->bank_name = plat->name; return 0; } static int gpio_dwapb_bind(struct udevice *dev) { struct gpio_dwapb_plat *plat = dev_get_plat(dev); struct udevice *subdev; fdt_addr_t base; int ret, bank = 0; ofnode node; /* If this is a child device, there is nothing to do here */ if (plat) return 0; base = dev_read_addr(dev); if (base == FDT_ADDR_T_NONE) { debug("Can't get the GPIO register base address\n"); return -ENXIO; } for (node = dev_read_first_subnode(dev); ofnode_valid(node); node = dev_read_next_subnode(node)) { if (!ofnode_read_bool(node, "gpio-controller")) continue; plat = devm_kcalloc(dev, 1, sizeof(*plat), GFP_KERNEL); if (!plat) return -ENOMEM; plat->base = (void *)base; plat->bank = bank; if (ofnode_read_u32(node, "ngpios", &plat->pins)) plat->pins = ofnode_read_u32_default(node, "snps,nr-gpios", 0); if (ofnode_read_string_index(node, "bank-name", 0, &plat->name)) { /* * Fall back to node name. This means accessing pins * via bank name won't work. */ char name[32]; snprintf(name, sizeof(name), "%s_", ofnode_get_name(node)); plat->name = strdup(name); if (!plat->name) { devm_kfree(dev, plat); return -ENOMEM; } } ret = device_bind(dev, dev->driver, plat->name, plat, node, &subdev); if (ret) return ret; bank++; } return 0; } static int gpio_dwapb_remove(struct udevice *dev) { struct gpio_dwapb_plat *plat = dev_get_plat(dev); struct gpio_dwapb_priv *priv = dev_get_priv(dev); if (!plat && priv) return reset_release_bulk(&priv->resets); return 0; } static const struct udevice_id gpio_dwapb_ids[] = { { .compatible = "snps,dw-apb-gpio" }, { } }; U_BOOT_DRIVER(gpio_dwapb) = { .name = "gpio-dwapb", .id = UCLASS_GPIO, .of_match = gpio_dwapb_ids, .ops = &gpio_dwapb_ops, .bind = gpio_dwapb_bind, .probe = gpio_dwapb_probe, .remove = gpio_dwapb_remove, .priv_auto = sizeof(struct gpio_dwapb_priv), }; |