1 /* 2 * (C) Copyright 2015 Marek Vasut <marex@denx.de> 3 * 4 * DesignWare APB GPIO driver 5 * 6 * SPDX-License-Identifier: GPL-2.0+ 7 */ 8 9 #include <common.h> 10 #include <malloc.h> 11 #include <asm/arch/gpio.h> 12 #include <asm/gpio.h> 13 #include <asm/io.h> 14 #include <dm.h> 15 #include <dm/device-internal.h> 16 #include <dm/lists.h> 17 #include <dm/root.h> 18 #include <errno.h> 19 20 DECLARE_GLOBAL_DATA_PTR; 21 22 #define GPIO_SWPORT_DR(p) (0x00 + (p) * 0xc) 23 #define GPIO_SWPORT_DDR(p) (0x04 + (p) * 0xc) 24 #define GPIO_INTEN 0x30 25 #define GPIO_INTMASK 0x34 26 #define GPIO_INTTYPE_LEVEL 0x38 27 #define GPIO_INT_POLARITY 0x3c 28 #define GPIO_INTSTATUS 0x40 29 #define GPIO_PORTA_DEBOUNCE 0x48 30 #define GPIO_PORTA_EOI 0x4c 31 #define GPIO_EXT_PORT(p) (0x50 + (p) * 4) 32 33 struct gpio_dwapb_platdata { 34 const char *name; 35 int bank; 36 int pins; 37 fdt_addr_t base; 38 }; 39 40 static int dwapb_gpio_direction_input(struct udevice *dev, unsigned pin) 41 { 42 struct gpio_dwapb_platdata *plat = dev_get_platdata(dev); 43 44 clrbits_le32(plat->base + GPIO_SWPORT_DDR(plat->bank), 1 << pin); 45 return 0; 46 } 47 48 static int dwapb_gpio_direction_output(struct udevice *dev, unsigned pin, 49 int val) 50 { 51 struct gpio_dwapb_platdata *plat = dev_get_platdata(dev); 52 53 setbits_le32(plat->base + GPIO_SWPORT_DDR(plat->bank), 1 << pin); 54 55 if (val) 56 setbits_le32(plat->base + GPIO_SWPORT_DR(plat->bank), 1 << pin); 57 else 58 clrbits_le32(plat->base + GPIO_SWPORT_DR(plat->bank), 1 << pin); 59 60 return 0; 61 } 62 63 static int dwapb_gpio_get_value(struct udevice *dev, unsigned pin) 64 { 65 struct gpio_dwapb_platdata *plat = dev_get_platdata(dev); 66 return !!(readl(plat->base + GPIO_EXT_PORT(plat->bank)) & (1 << pin)); 67 } 68 69 70 static int dwapb_gpio_set_value(struct udevice *dev, unsigned pin, int val) 71 { 72 struct gpio_dwapb_platdata *plat = dev_get_platdata(dev); 73 74 if (val) 75 setbits_le32(plat->base + GPIO_SWPORT_DR(plat->bank), 1 << pin); 76 else 77 clrbits_le32(plat->base + GPIO_SWPORT_DR(plat->bank), 1 << pin); 78 79 return 0; 80 } 81 82 static const struct dm_gpio_ops gpio_dwapb_ops = { 83 .direction_input = dwapb_gpio_direction_input, 84 .direction_output = dwapb_gpio_direction_output, 85 .get_value = dwapb_gpio_get_value, 86 .set_value = dwapb_gpio_set_value, 87 }; 88 89 static int gpio_dwapb_probe(struct udevice *dev) 90 { 91 struct gpio_dev_priv *priv = dev_get_uclass_priv(dev); 92 struct gpio_dwapb_platdata *plat = dev->platdata; 93 94 if (!plat) 95 return 0; 96 97 priv->gpio_count = plat->pins; 98 priv->bank_name = plat->name; 99 100 return 0; 101 } 102 103 static int gpio_dwapb_bind(struct udevice *dev) 104 { 105 struct gpio_dwapb_platdata *plat = dev_get_platdata(dev); 106 const void *blob = gd->fdt_blob; 107 struct udevice *subdev; 108 fdt_addr_t base; 109 int ret, node, bank = 0; 110 111 /* If this is a child device, there is nothing to do here */ 112 if (plat) 113 return 0; 114 115 base = fdtdec_get_addr(blob, dev_of_offset(dev), "reg"); 116 if (base == FDT_ADDR_T_NONE) { 117 debug("Can't get the GPIO register base address\n"); 118 return -ENXIO; 119 } 120 121 for (node = fdt_first_subnode(blob, dev_of_offset(dev)); 122 node > 0; 123 node = fdt_next_subnode(blob, node)) { 124 if (!fdtdec_get_bool(blob, node, "gpio-controller")) 125 continue; 126 127 plat = NULL; 128 plat = calloc(1, sizeof(*plat)); 129 if (!plat) 130 return -ENOMEM; 131 132 plat->base = base; 133 plat->bank = bank; 134 plat->pins = fdtdec_get_int(blob, node, "snps,nr-gpios", 0); 135 plat->name = fdt_stringlist_get(blob, node, "bank-name", 0, 136 NULL); 137 if (ret) 138 goto err; 139 140 ret = device_bind(dev, dev->driver, plat->name, 141 plat, -1, &subdev); 142 if (ret) 143 goto err; 144 145 dev_set_of_offset(subdev, node); 146 bank++; 147 } 148 149 return 0; 150 151 err: 152 free(plat); 153 return ret; 154 } 155 156 static const struct udevice_id gpio_dwapb_ids[] = { 157 { .compatible = "snps,dw-apb-gpio" }, 158 { } 159 }; 160 161 U_BOOT_DRIVER(gpio_dwapb) = { 162 .name = "gpio-dwapb", 163 .id = UCLASS_GPIO, 164 .of_match = gpio_dwapb_ids, 165 .ops = &gpio_dwapb_ops, 166 .bind = gpio_dwapb_bind, 167 .probe = gpio_dwapb_probe, 168 }; 169