1 /* $OpenBSD: exgpio.c,v 1.4 2016/07/26 22:10:10 patrick Exp $ */ 2 /* 3 * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> 4 * Copyright (c) 2012-2013 Patrick Wildt <patrick@blueri.se> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/param.h> 20 #include <sys/systm.h> 21 #include <sys/queue.h> 22 #include <sys/device.h> 23 #include <sys/malloc.h> 24 #include <sys/evcount.h> 25 26 #include <arm/cpufunc.h> 27 28 #include <machine/bus.h> 29 #if NFDT > 0 30 #include <machine/fdt.h> 31 #endif 32 #include <machine/intr.h> 33 34 #include <armv7/armv7/armv7var.h> 35 #include <armv7/exynos/exgpiovar.h> 36 37 /* Exynos5 registers */ 38 #define GPIO_BANK_SIZE 0x20 39 #define GPIO_BANK(x) (GPIO_BANK_SIZE * ((x) / 8)) 40 #define GPIO_CON(x) (GPIO_BANK(x) + 0x00) 41 #define GPIO_DAT(x) (GPIO_BANK(x) + 0x04) 42 #define GPIO_PULL(x) (GPIO_BANK(x) + 0x08) 43 #define GPIO_DRV(x) (GPIO_BANK(x) + 0x0c) 44 #define GPIO_PDN_CON(x) (GPIO_BANK(x) + 0x10) 45 #define GPIO_PDN_PULL(x) (GPIO_BANK(x) + 0x14) 46 47 /* bits and bytes */ 48 #define GPIO_PIN(x) ((x) % 8) 49 #define GPIO_CON_INPUT(x) (0x0 << (GPIO_PIN(x) << 2)) 50 #define GPIO_CON_OUTPUT(x) (0x1 << (GPIO_PIN(x) << 2)) 51 #define GPIO_CON_IRQ(x) (0xf << (GPIO_PIN(x) << 2)) 52 #define GPIO_CON_MASK(x) (0xf << (GPIO_PIN(x) << 2)) 53 #define GPIO_DAT_SET(x) (0x1 << (GPIO_PIN(x) << 0)) 54 #define GPIO_DAT_MASK(x) (0x1 << (GPIO_PIN(x) << 0)) 55 #define GPIO_PULL_NONE(x) (0x0 << (GPIO_PIN(x) << 1)) 56 #define GPIO_PULL_DOWN(x) (0x1 << (GPIO_PIN(x) << 1)) 57 #define GPIO_PULL_UP(x) (0x3 << (GPIO_PIN(x) << 1)) 58 #define GPIO_PULL_MASK(x) (0x3 << (GPIO_PIN(x) << 1)) 59 #define GPIO_DRV_1X(x) (0x0 << (GPIO_PIN(x) << 1)) 60 #define GPIO_DRV_2X(x) (0x1 << (GPIO_PIN(x) << 1)) 61 #define GPIO_DRV_3X(x) (0x2 << (GPIO_PIN(x) << 1)) 62 #define GPIO_DRV_4X(x) (0x3 << (GPIO_PIN(x) << 1)) 63 #define GPIO_DRV_MASK(x) (0x3 << (GPIO_PIN(x) << 1)) 64 65 #define GPIO_PINS_PER_BANK 8 66 67 struct exgpio_softc { 68 struct device sc_dev; 69 bus_space_tag_t sc_iot; 70 bus_space_handle_t sc_ioh; 71 int sc_ngpio; 72 unsigned int (*sc_get_bit)(struct exgpio_softc *sc, 73 unsigned int gpio); 74 void (*sc_set_bit)(struct exgpio_softc *sc, 75 unsigned int gpio); 76 void (*sc_clear_bit)(struct exgpio_softc *sc, 77 unsigned int gpio); 78 void (*sc_set_dir)(struct exgpio_softc *sc, 79 unsigned int gpio, unsigned int dir); 80 }; 81 82 int exgpio_match(struct device *parent, void *v, void *aux); 83 void exgpio_attach(struct device *parent, struct device *self, void *args); 84 85 struct exgpio_softc *exgpio_pin_to_inst(unsigned int); 86 unsigned int exgpio_pin_to_offset(unsigned int); 87 unsigned int exgpio_v5_get_bit(struct exgpio_softc *, unsigned int); 88 void exgpio_v5_set_bit(struct exgpio_softc *, unsigned int); 89 void exgpio_v5_clear_bit(struct exgpio_softc *, unsigned int); 90 void exgpio_v5_set_dir(struct exgpio_softc *, unsigned int, unsigned int); 91 unsigned int exgpio_v5_get_dir(struct exgpio_softc *, unsigned int); 92 93 94 struct cfattach exgpio_ca = { 95 sizeof (struct exgpio_softc), NULL, exgpio_attach 96 }; 97 struct cfattach exgpio_fdt_ca = { 98 sizeof (struct exgpio_softc), exgpio_match, exgpio_attach 99 }; 100 101 struct cfdriver exgpio_cd = { 102 NULL, "exgpio", DV_DULL 103 }; 104 105 int 106 exgpio_match(struct device *parent, void *v, void *aux) 107 { 108 #if NFDT > 0 109 struct armv7_attach_args *aa = aux; 110 111 if (fdt_node_compatible("samsung,exynos5250-pinctrl", aa->aa_node)) 112 return 1; 113 #endif 114 115 return 0; 116 } 117 118 void 119 exgpio_attach(struct device *parent, struct device *self, void *args) 120 { 121 struct armv7_attach_args *aa = args; 122 struct exgpio_softc *sc = (struct exgpio_softc *) self; 123 struct armv7mem mem; 124 125 sc->sc_iot = aa->aa_iot; 126 #if NFDT > 0 127 if (aa->aa_node) { 128 struct fdt_reg reg; 129 if (fdt_get_reg(aa->aa_node, 0, ®)) 130 panic("%s: could not extract memory data from FDT", 131 __func__); 132 mem.addr = reg.addr; 133 mem.size = reg.size; 134 } else 135 #endif 136 { 137 mem.addr = aa->aa_dev->mem[0].addr; 138 mem.size = aa->aa_dev->mem[0].size; 139 } 140 if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh)) 141 panic("%s: bus_space_map failed!", __func__); 142 143 sc->sc_ngpio = (mem.size / GPIO_BANK_SIZE) * GPIO_PINS_PER_BANK; 144 145 sc->sc_get_bit = exgpio_v5_get_bit; 146 sc->sc_set_bit = exgpio_v5_set_bit; 147 sc->sc_clear_bit = exgpio_v5_clear_bit; 148 sc->sc_set_dir = exgpio_v5_set_dir; 149 150 printf("\n"); 151 152 /* XXX - IRQ */ 153 /* XXX - SYSCONFIG */ 154 /* XXX - CTRL */ 155 /* XXX - DEBOUNCE */ 156 } 157 158 struct exgpio_softc * 159 exgpio_pin_to_inst(unsigned int gpio) 160 { 161 int i; 162 163 for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++) 164 { 165 struct exgpio_softc *sc = exgpio_cd.cd_devs[i]; 166 if (gpio < sc->sc_ngpio) 167 return sc; 168 else 169 gpio -= sc->sc_ngpio; 170 } 171 172 return NULL; 173 } 174 175 unsigned int 176 exgpio_pin_to_offset(unsigned int gpio) 177 { 178 int i; 179 180 for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++) 181 { 182 struct exgpio_softc *sc = exgpio_cd.cd_devs[i]; 183 if (gpio < sc->sc_ngpio) 184 return gpio; 185 else 186 gpio -= sc->sc_ngpio; 187 } 188 189 return 0; 190 } 191 192 unsigned int 193 exgpio_get_bit(unsigned int gpio) 194 { 195 struct exgpio_softc *sc = exgpio_pin_to_inst(gpio); 196 197 return sc->sc_get_bit(sc, gpio); 198 } 199 200 void 201 exgpio_set_bit(unsigned int gpio) 202 { 203 struct exgpio_softc *sc = exgpio_pin_to_inst(gpio); 204 205 sc->sc_set_bit(sc, gpio); 206 } 207 208 void 209 exgpio_clear_bit(unsigned int gpio) 210 { 211 struct exgpio_softc *sc = exgpio_pin_to_inst(gpio); 212 213 sc->sc_clear_bit(sc, gpio); 214 } 215 void 216 exgpio_set_dir(unsigned int gpio, unsigned int dir) 217 { 218 struct exgpio_softc *sc = exgpio_pin_to_inst(gpio); 219 220 sc->sc_set_dir(sc, gpio, dir); 221 } 222 223 unsigned int 224 exgpio_v5_get_bit(struct exgpio_softc *sc, unsigned int gpio) 225 { 226 u_int32_t val; 227 228 gpio = exgpio_pin_to_offset(gpio); 229 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio)); 230 231 return !!(val & GPIO_DAT_SET(gpio)); 232 } 233 234 void 235 exgpio_v5_set_bit(struct exgpio_softc *sc, unsigned int gpio) 236 { 237 u_int32_t val; 238 239 gpio = exgpio_pin_to_offset(gpio); 240 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio)); 241 242 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio), 243 val | GPIO_DAT_SET(gpio)); 244 } 245 246 void 247 exgpio_v5_clear_bit(struct exgpio_softc *sc, unsigned int gpio) 248 { 249 u_int32_t val; 250 251 gpio = exgpio_pin_to_offset(gpio); 252 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio)); 253 254 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio), 255 val & ~GPIO_DAT_MASK(gpio)); 256 } 257 258 void 259 exgpio_v5_set_dir(struct exgpio_softc *sc, unsigned int gpio, unsigned int dir) 260 { 261 int s; 262 u_int32_t val; 263 264 gpio = exgpio_pin_to_offset(gpio); 265 s = splhigh(); 266 267 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio)); 268 val &= ~GPIO_CON_OUTPUT(gpio); 269 if (dir == EXGPIO_DIR_OUT) 270 val |= GPIO_CON_OUTPUT(gpio); 271 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio), val); 272 273 splx(s); 274 } 275 276 unsigned int 277 exgpio_v5_get_dir(struct exgpio_softc *sc, unsigned int gpio) 278 { 279 int s; 280 u_int32_t val; 281 282 gpio = exgpio_pin_to_offset(gpio); 283 s = splhigh(); 284 285 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio)); 286 if (val & GPIO_CON_OUTPUT(gpio)) 287 val = EXGPIO_DIR_OUT; 288 else 289 val = EXGPIO_DIR_IN; 290 291 splx(s); 292 return val; 293 } 294