1 /* $OpenBSD: exgpio.c,v 1.1 2015/01/26 02:48:24 bmercer 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 #include <machine/fdt.h> 30 #include <machine/intr.h> 31 32 #include <armv7/armv7/armv7var.h> 33 #include <armv7/exynos/exgpiovar.h> 34 35 /* Exynos5 registers */ 36 #define GPIO_BANK_SIZE 0x20 37 #define GPIO_BANK(x) (GPIO_BANK_SIZE * ((x) / 8)) 38 #define GPIO_CON(x) (GPIO_BANK(x) + 0x00) 39 #define GPIO_DAT(x) (GPIO_BANK(x) + 0x04) 40 #define GPIO_PULL(x) (GPIO_BANK(x) + 0x08) 41 #define GPIO_DRV(x) (GPIO_BANK(x) + 0x0c) 42 #define GPIO_PDN_CON(x) (GPIO_BANK(x) + 0x10) 43 #define GPIO_PDN_PULL(x) (GPIO_BANK(x) + 0x14) 44 45 /* bits and bytes */ 46 #define GPIO_PIN(x) ((x) % 8) 47 #define GPIO_CON_INPUT(x) (0x0 << (GPIO_PIN(x) << 2)) 48 #define GPIO_CON_OUTPUT(x) (0x1 << (GPIO_PIN(x) << 2)) 49 #define GPIO_CON_IRQ(x) (0xf << (GPIO_PIN(x) << 2)) 50 #define GPIO_CON_MASK(x) (0xf << (GPIO_PIN(x) << 2)) 51 #define GPIO_DAT_SET(x) (0x1 << (GPIO_PIN(x) << 0)) 52 #define GPIO_DAT_MASK(x) (0x1 << (GPIO_PIN(x) << 0)) 53 #define GPIO_PULL_NONE(x) (0x0 << (GPIO_PIN(x) << 1)) 54 #define GPIO_PULL_DOWN(x) (0x1 << (GPIO_PIN(x) << 1)) 55 #define GPIO_PULL_UP(x) (0x3 << (GPIO_PIN(x) << 1)) 56 #define GPIO_PULL_MASK(x) (0x3 << (GPIO_PIN(x) << 1)) 57 #define GPIO_DRV_1X(x) (0x0 << (GPIO_PIN(x) << 1)) 58 #define GPIO_DRV_2X(x) (0x1 << (GPIO_PIN(x) << 1)) 59 #define GPIO_DRV_3X(x) (0x2 << (GPIO_PIN(x) << 1)) 60 #define GPIO_DRV_4X(x) (0x3 << (GPIO_PIN(x) << 1)) 61 #define GPIO_DRV_MASK(x) (0x3 << (GPIO_PIN(x) << 1)) 62 63 #define GPIO_PINS_PER_BANK 8 64 65 struct exgpio_softc { 66 struct device sc_dev; 67 bus_space_tag_t sc_iot; 68 bus_space_handle_t sc_ioh; 69 int sc_ngpio; 70 unsigned int (*sc_get_bit)(struct exgpio_softc *sc, 71 unsigned int gpio); 72 void (*sc_set_bit)(struct exgpio_softc *sc, 73 unsigned int gpio); 74 void (*sc_clear_bit)(struct exgpio_softc *sc, 75 unsigned int gpio); 76 void (*sc_set_dir)(struct exgpio_softc *sc, 77 unsigned int gpio, unsigned int dir); 78 }; 79 80 int exgpio_match(struct device *parent, void *v, void *aux); 81 void exgpio_attach(struct device *parent, struct device *self, void *args); 82 83 struct exgpio_softc *exgpio_pin_to_inst(unsigned int); 84 unsigned int exgpio_pin_to_offset(unsigned int); 85 unsigned int exgpio_v5_get_bit(struct exgpio_softc *, unsigned int); 86 void exgpio_v5_set_bit(struct exgpio_softc *, unsigned int); 87 void exgpio_v5_clear_bit(struct exgpio_softc *, unsigned int); 88 void exgpio_v5_set_dir(struct exgpio_softc *, unsigned int, unsigned int); 89 unsigned int exgpio_v5_get_dir(struct exgpio_softc *, unsigned int); 90 91 92 struct cfattach exgpio_ca = { 93 sizeof (struct exgpio_softc), NULL, exgpio_attach 94 }; 95 struct cfattach exgpio_fdt_ca = { 96 sizeof (struct exgpio_softc), exgpio_match, exgpio_attach 97 }; 98 99 struct cfdriver exgpio_cd = { 100 NULL, "exgpio", DV_DULL 101 }; 102 103 int 104 exgpio_match(struct device *parent, void *v, void *aux) 105 { 106 struct armv7_attach_args *aa = aux; 107 108 if (fdt_node_compatible("samsung,exynos5250-pinctrl", aa->aa_node)) 109 return 1; 110 111 return 0; 112 } 113 114 void 115 exgpio_attach(struct device *parent, struct device *self, void *args) 116 { 117 struct armv7_attach_args *aa = args; 118 struct exgpio_softc *sc = (struct exgpio_softc *) self; 119 struct fdt_memory mem; 120 121 sc->sc_iot = aa->aa_iot; 122 if (aa->aa_node) { 123 if (fdt_get_memory_address(aa->aa_node, 0, &mem)) 124 panic("%s: could not extract memory data from FDT", 125 __func__); 126 } else { 127 mem.addr = aa->aa_dev->mem[0].addr; 128 mem.size = aa->aa_dev->mem[0].size; 129 } 130 if (bus_space_map(sc->sc_iot, mem.addr, mem.size, 0, &sc->sc_ioh)) 131 panic("%s: bus_space_map failed!", __func__); 132 133 sc->sc_ngpio = (mem.size / GPIO_BANK_SIZE) * GPIO_PINS_PER_BANK; 134 135 sc->sc_get_bit = exgpio_v5_get_bit; 136 sc->sc_set_bit = exgpio_v5_set_bit; 137 sc->sc_clear_bit = exgpio_v5_clear_bit; 138 sc->sc_set_dir = exgpio_v5_set_dir; 139 140 printf("\n"); 141 142 /* XXX - IRQ */ 143 /* XXX - SYSCONFIG */ 144 /* XXX - CTRL */ 145 /* XXX - DEBOUNCE */ 146 } 147 148 struct exgpio_softc * 149 exgpio_pin_to_inst(unsigned int gpio) 150 { 151 int i; 152 153 for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++) 154 { 155 struct exgpio_softc *sc = exgpio_cd.cd_devs[i]; 156 if (gpio < sc->sc_ngpio) 157 return sc; 158 else 159 gpio -= sc->sc_ngpio; 160 } 161 162 return NULL; 163 } 164 165 unsigned int 166 exgpio_pin_to_offset(unsigned int gpio) 167 { 168 int i; 169 170 for (i = 0; exgpio_cd.cd_devs[i] != NULL; i++) 171 { 172 struct exgpio_softc *sc = exgpio_cd.cd_devs[i]; 173 if (gpio < sc->sc_ngpio) 174 return gpio; 175 else 176 gpio -= sc->sc_ngpio; 177 } 178 179 return 0; 180 } 181 182 unsigned int 183 exgpio_get_bit(unsigned int gpio) 184 { 185 struct exgpio_softc *sc = exgpio_pin_to_inst(gpio); 186 187 return sc->sc_get_bit(sc, gpio); 188 } 189 190 void 191 exgpio_set_bit(unsigned int gpio) 192 { 193 struct exgpio_softc *sc = exgpio_pin_to_inst(gpio); 194 195 sc->sc_set_bit(sc, gpio); 196 } 197 198 void 199 exgpio_clear_bit(unsigned int gpio) 200 { 201 struct exgpio_softc *sc = exgpio_pin_to_inst(gpio); 202 203 sc->sc_clear_bit(sc, gpio); 204 } 205 void 206 exgpio_set_dir(unsigned int gpio, unsigned int dir) 207 { 208 struct exgpio_softc *sc = exgpio_pin_to_inst(gpio); 209 210 sc->sc_set_dir(sc, gpio, dir); 211 } 212 213 unsigned int 214 exgpio_v5_get_bit(struct exgpio_softc *sc, unsigned int gpio) 215 { 216 u_int32_t val; 217 218 gpio = exgpio_pin_to_offset(gpio); 219 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio)); 220 221 return !!(val & GPIO_DAT_SET(gpio)); 222 } 223 224 void 225 exgpio_v5_set_bit(struct exgpio_softc *sc, unsigned int gpio) 226 { 227 u_int32_t val; 228 229 gpio = exgpio_pin_to_offset(gpio); 230 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio)); 231 232 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio), 233 val | GPIO_DAT_SET(gpio)); 234 } 235 236 void 237 exgpio_v5_clear_bit(struct exgpio_softc *sc, unsigned int gpio) 238 { 239 u_int32_t val; 240 241 gpio = exgpio_pin_to_offset(gpio); 242 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio)); 243 244 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_DAT(gpio), 245 val & ~GPIO_DAT_MASK(gpio)); 246 } 247 248 void 249 exgpio_v5_set_dir(struct exgpio_softc *sc, unsigned int gpio, unsigned int dir) 250 { 251 int s; 252 u_int32_t val; 253 254 gpio = exgpio_pin_to_offset(gpio); 255 s = splhigh(); 256 257 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio)); 258 val &= ~GPIO_CON_OUTPUT(gpio); 259 if (dir == EXGPIO_DIR_OUT) 260 val |= GPIO_CON_OUTPUT(gpio); 261 bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio), val); 262 263 splx(s); 264 } 265 266 unsigned int 267 exgpio_v5_get_dir(struct exgpio_softc *sc, unsigned int gpio) 268 { 269 int s; 270 u_int32_t val; 271 272 gpio = exgpio_pin_to_offset(gpio); 273 s = splhigh(); 274 275 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO_CON(gpio)); 276 if (val & GPIO_CON_OUTPUT(gpio)) 277 val = EXGPIO_DIR_OUT; 278 else 279 val = EXGPIO_DIR_IN; 280 281 splx(s); 282 return val; 283 } 284