1 /* $NetBSD: augpio.c,v 1.5 2006/03/24 18:22:42 gdamore Exp $ */ 2 3 /*- 4 * Copyright (c) 2006 Itronix Inc. 5 * All rights reserved. 6 * 7 * Written by Garrett D'Amore for Itronix Inc. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of Itronix Inc. may not be used to endorse 18 * or promote products derived from this software without specific 19 * prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY ITRONIX INC. ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 23 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ITRONIX INC. BE LIABLE FOR ANY 25 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 26 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 27 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 28 * ON ANY THEORY OF LIABILITY, WHETHER IN 29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 31 * POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: augpio.c,v 1.5 2006/03/24 18:22:42 gdamore Exp $"); 36 37 #include <sys/types.h> 38 #include <sys/param.h> 39 #include <sys/systm.h> 40 #include <sys/errno.h> 41 #include <sys/device.h> 42 #include <sys/gpio.h> 43 #include <sys/kernel.h> 44 45 #include <dev/gpio/gpiovar.h> 46 47 #include <machine/bus.h> 48 #include <machine/cpu.h> 49 50 #include <mips/alchemy/include/aubusvar.h> 51 #include <mips/alchemy/include/aureg.h> 52 #include <mips/alchemy/dev/augpioreg.h> 53 #include <mips/alchemy/dev/augpiovar.h> 54 55 struct augpio_softc { 56 struct device sc_dev; 57 struct gpio_chipset_tag sc_gc; 58 gpio_pin_t sc_pins[AUGPIO_NPINS]; 59 int sc_npins; 60 bus_space_tag_t sc_bst; 61 int sc_caps; 62 const char *sc_name; 63 int (*sc_getctl)(void *, int); 64 }; 65 66 static int augpio_match(struct device *, struct cfdata *, void *); 67 static void augpio_attach(struct device *, struct device *, void *); 68 69 CFATTACH_DECL(augpio, sizeof(struct augpio_softc), 70 augpio_match, augpio_attach, NULL, NULL); 71 72 #define GETREG(x) \ 73 (*(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(x)) 74 #define PUTREG(x, v) \ 75 ((*(volatile uint32_t *)MIPS_PHYS_TO_KSEG1(x)) = (v)) 76 77 #define GETGPIO(x) GETREG(GPIO_BASE + (x)) 78 #define PUTGPIO(x,v) PUTREG(GPIO_BASE + (x), (v)) 79 #define GETGPIO2(x) GETREG(GPIO2_BASE + (x)) 80 #define PUTGPIO2(x,v) PUTREG(GPIO2_BASE + (x), (v)) 81 82 int 83 augpio_match(struct device *parent, struct cfdata *match, void *aux) 84 { 85 struct aubus_attach_args *aa = (struct aubus_attach_args *)aux; 86 87 if (strcmp(aa->aa_name, "augpio") != 0) 88 return 0; 89 90 return 1; 91 } 92 93 void 94 augpio_attach(struct device *parent, struct device *self, void *aux) 95 { 96 int pin; 97 98 struct augpio_softc *sc = (struct augpio_softc *)self; 99 struct aubus_attach_args *aa = aux; 100 struct gpiobus_attach_args gba; 101 102 sc->sc_bst = aa->aa_st; 103 sc->sc_npins = aa->aa_addrs[1]; 104 sc->sc_gc.gp_cookie = sc; 105 106 if (aa->aa_addrs[0] == GPIO_BASE) { 107 108 sc->sc_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | 109 GPIO_PIN_TRISTATE; 110 sc->sc_gc.gp_pin_read = augpio_read; 111 sc->sc_gc.gp_pin_write = augpio_write; 112 sc->sc_gc.gp_pin_ctl = augpio_ctl; 113 sc->sc_getctl = augpio_getctl; 114 sc->sc_name = "primary block"; 115 116 } else if (aa->aa_addrs[0] == GPIO2_BASE) { 117 /* 118 * We rely on firmware (or platform init code) to initialize 119 * the GPIO2 block. We can't do it ourselves, because 120 * resetting the GPIO2 block can have nasty effects (e.g. 121 * reset PCI bus...) 122 */ 123 sc->sc_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; 124 sc->sc_gc.gp_pin_read = augpio2_read; 125 sc->sc_gc.gp_pin_write = augpio2_write; 126 sc->sc_gc.gp_pin_ctl = augpio2_ctl; 127 sc->sc_getctl = augpio2_getctl; 128 sc->sc_name = "secondary block"; 129 130 } else { 131 printf(": unidentified block\n"); 132 return; 133 } 134 135 for (pin = 0; pin < sc->sc_npins; pin++) { 136 gpio_pin_t *pp = &sc->sc_pins[pin]; 137 138 pp->pin_num = pin; 139 pp->pin_caps = sc->sc_caps; 140 pp->pin_flags = sc->sc_getctl(sc, pin); 141 pp->pin_state = sc->sc_gc.gp_pin_read(sc, pin); 142 } 143 144 gba.gba_gc = &sc->sc_gc; 145 gba.gba_pins = sc->sc_pins; 146 gba.gba_npins = sc->sc_npins; 147 148 printf(": Alchemy GPIO, %s\n", sc->sc_name); 149 config_found_ia(&sc->sc_dev, "gpiobus", &gba, gpiobus_print); 150 } 151 152 int 153 augpio_read(void *arg, int pin) 154 { 155 156 pin = 1 << pin; 157 158 if (GETGPIO(AUGPIO_PINSTATERD) & pin) 159 return GPIO_PIN_HIGH; 160 else 161 return GPIO_PIN_LOW; 162 } 163 164 void 165 augpio_write(void *arg, int pin, int value) 166 { 167 168 pin = 1 << pin; 169 PUTGPIO(value ? AUGPIO_OUTPUTSET : AUGPIO_OUTPUTCLR, pin); 170 } 171 172 void 173 augpio_ctl(void *arg, int pin, int flags) 174 { 175 bus_addr_t reg; 176 177 pin = 1 << pin; 178 179 if (flags & (GPIO_PIN_TRISTATE|GPIO_PIN_INPUT)) { 180 reg = AUGPIO_TRIOUTCLR; 181 } else if (flags & GPIO_PIN_OUTPUT) { 182 uint32_t out; 183 out = GETGPIO(AUGPIO_OUTPUTRD); 184 reg = pin & out ? AUGPIO_OUTPUTSET : AUGPIO_OUTPUTCLR; 185 } else { 186 return; 187 } 188 189 PUTGPIO(reg, pin); 190 } 191 192 int 193 augpio_getctl(void *arg, int pin) 194 { 195 196 if (GETGPIO(AUGPIO_TRIOUTRD) & pin) 197 return GPIO_PIN_OUTPUT; 198 else 199 return GPIO_PIN_INPUT; 200 } 201 202 int 203 augpio2_read(void *arg, int pin) 204 { 205 206 pin = 1 << pin; 207 208 if (GETGPIO2(AUGPIO2_PINSTATE) & pin) 209 return GPIO_PIN_HIGH; 210 else 211 return GPIO_PIN_LOW; 212 } 213 214 void 215 augpio2_write(void *arg, int pin, int value) 216 { 217 218 pin = 1 << pin; 219 220 if (value) { 221 pin = pin | (pin << 16); 222 } else { 223 pin = (pin << 16); 224 } 225 226 PUTGPIO2(AUGPIO2_OUTPUT, pin); 227 } 228 229 void 230 augpio2_ctl(void *arg, int pin, int flags) 231 { 232 uint32_t dir; 233 234 pin = 1 << pin; 235 236 dir = GETGPIO2(AUGPIO2_DIR); 237 238 if (flags & GPIO_PIN_INPUT) { 239 dir |= pin; 240 } else if (flags & GPIO_PIN_OUTPUT) { 241 dir &= ~pin; 242 } 243 PUTGPIO2(AUGPIO2_DIR, dir); 244 } 245 246 int 247 augpio2_getctl(void *arg, int pin) 248 { 249 uint32_t dir; 250 251 pin = 1 << pin; 252 253 dir = GETGPIO2(AUGPIO2_DIR); 254 if (dir & (uint32_t)pin) { 255 return GPIO_PIN_OUTPUT; 256 } else { 257 return GPIO_PIN_INPUT; 258 } 259 } 260 261