1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright (C) 2018 Stefan Roese <sr@denx.de> 4 * 5 * Based on the Linux driver version which is: 6 * Copyright (C) 2009-2011 Gabor Juhos <juhosg@openwrt.org> 7 * Copyright (C) 2013 John Crispin <blogic@openwrt.org> 8 */ 9 10 #include <common.h> 11 #include <dm.h> 12 #include <errno.h> 13 #include <fdtdec.h> 14 #include <malloc.h> 15 #include <linux/io.h> 16 #include <asm/io.h> 17 #include <asm/gpio.h> 18 #include <dm/device-internal.h> 19 #include <dt-bindings/gpio/gpio.h> 20 21 #define MTK_MAX_BANK 3 22 #define MTK_BANK_WIDTH 32 23 24 enum mediatek_gpio_reg { 25 GPIO_REG_CTRL = 0, 26 GPIO_REG_POL, 27 GPIO_REG_DATA, 28 GPIO_REG_DSET, 29 GPIO_REG_DCLR, 30 GPIO_REG_REDGE, 31 GPIO_REG_FEDGE, 32 GPIO_REG_HLVL, 33 GPIO_REG_LLVL, 34 GPIO_REG_STAT, 35 GPIO_REG_EDGE, 36 }; 37 38 static void __iomem *mediatek_gpio_membase; 39 40 struct mediatek_gpio_platdata { 41 char bank_name[3]; /* Name of bank, e.g. "PA", "PB" etc */ 42 int gpio_count; 43 int bank; 44 }; 45 46 static u32 reg_offs(struct mediatek_gpio_platdata *plat, int reg) 47 { 48 return (reg * 0x10) + (plat->bank * 0x4); 49 } 50 51 static int mediatek_gpio_get_value(struct udevice *dev, unsigned int offset) 52 { 53 struct mediatek_gpio_platdata *plat = dev_get_platdata(dev); 54 55 return !!(ioread32(mediatek_gpio_membase + 56 reg_offs(plat, GPIO_REG_DATA)) & BIT(offset)); 57 } 58 59 static int mediatek_gpio_set_value(struct udevice *dev, unsigned int offset, 60 int value) 61 { 62 struct mediatek_gpio_platdata *plat = dev_get_platdata(dev); 63 64 iowrite32(BIT(offset), mediatek_gpio_membase + 65 reg_offs(plat, value ? GPIO_REG_DSET : GPIO_REG_DCLR)); 66 67 return 0; 68 } 69 70 static int mediatek_gpio_direction_input(struct udevice *dev, unsigned int offset) 71 { 72 struct mediatek_gpio_platdata *plat = dev_get_platdata(dev); 73 74 clrbits_le32(mediatek_gpio_membase + reg_offs(plat, GPIO_REG_CTRL), 75 BIT(offset)); 76 77 return 0; 78 } 79 80 static int mediatek_gpio_direction_output(struct udevice *dev, unsigned int offset, 81 int value) 82 { 83 struct mediatek_gpio_platdata *plat = dev_get_platdata(dev); 84 85 setbits_le32(mediatek_gpio_membase + reg_offs(plat, GPIO_REG_CTRL), 86 BIT(offset)); 87 mediatek_gpio_set_value(dev, offset, value); 88 89 return 0; 90 } 91 92 static int mediatek_gpio_get_function(struct udevice *dev, unsigned int offset) 93 { 94 struct mediatek_gpio_platdata *plat = dev_get_platdata(dev); 95 u32 t; 96 97 t = ioread32(mediatek_gpio_membase + reg_offs(plat, GPIO_REG_CTRL)); 98 if (t & BIT(offset)) 99 return GPIOF_OUTPUT; 100 101 return GPIOF_INPUT; 102 } 103 104 static const struct dm_gpio_ops gpio_mediatek_ops = { 105 .direction_input = mediatek_gpio_direction_input, 106 .direction_output = mediatek_gpio_direction_output, 107 .get_value = mediatek_gpio_get_value, 108 .set_value = mediatek_gpio_set_value, 109 .get_function = mediatek_gpio_get_function, 110 }; 111 112 static int gpio_mediatek_probe(struct udevice *dev) 113 { 114 struct mediatek_gpio_platdata *plat = dev_get_platdata(dev); 115 struct gpio_dev_priv *uc_priv = dev_get_uclass_priv(dev); 116 117 /* Tell the uclass how many GPIOs we have */ 118 if (plat) { 119 uc_priv->gpio_count = plat->gpio_count; 120 uc_priv->bank_name = plat->bank_name; 121 } 122 123 return 0; 124 } 125 126 /** 127 * We have a top-level GPIO device with no actual GPIOs. It has a child 128 * device for each Mediatek bank. 129 */ 130 static int gpio_mediatek_bind(struct udevice *parent) 131 { 132 struct mediatek_gpio_platdata *plat = parent->platdata; 133 ofnode node; 134 int bank = 0; 135 int ret; 136 137 /* If this is a child device, there is nothing to do here */ 138 if (plat) 139 return 0; 140 141 mediatek_gpio_membase = dev_remap_addr(parent); 142 if (!mediatek_gpio_membase) 143 return -EINVAL; 144 145 for (node = dev_read_first_subnode(parent); ofnode_valid(node); 146 node = dev_read_next_subnode(node)) { 147 struct mediatek_gpio_platdata *plat; 148 struct udevice *dev; 149 150 plat = calloc(1, sizeof(*plat)); 151 if (!plat) 152 return -ENOMEM; 153 plat->bank_name[0] = 'P'; 154 plat->bank_name[1] = 'A' + bank; 155 plat->bank_name[2] = '\0'; 156 plat->gpio_count = MTK_BANK_WIDTH; 157 plat->bank = bank; 158 159 ret = device_bind(parent, parent->driver, 160 plat->bank_name, plat, -1, &dev); 161 if (ret) 162 return ret; 163 164 dev->node = node; 165 bank++; 166 } 167 168 return 0; 169 } 170 171 static const struct udevice_id mediatek_gpio_ids[] = { 172 { .compatible = "mtk,mt7621-gpio" }, 173 { } 174 }; 175 176 U_BOOT_DRIVER(gpio_mediatek) = { 177 .name = "gpio_mediatek", 178 .id = UCLASS_GPIO, 179 .ops = &gpio_mediatek_ops, 180 .of_match = mediatek_gpio_ids, 181 .bind = gpio_mediatek_bind, 182 .probe = gpio_mediatek_probe, 183 }; 184