1 /* $NetBSD: bcm2835_gpio.c,v 1.3 2016/02/02 13:55:50 skrll Exp $ */ 2 3 /*- 4 * Copyright (c) 2014 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Frank Kardel. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 23 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 24 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 25 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 26 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 27 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 28 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 29 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __KERNEL_RCSID(0, "$NetBSD: bcm2835_gpio.c,v 1.3 2016/02/02 13:55:50 skrll Exp $"); 34 35 /* 36 * Driver for BCM2835 GPIO 37 * 38 * see: http://www.raspberrypi.org/wp-content/uploads/2012/02/BCM2835-ARM-Peripherals.pdf 39 */ 40 41 #include "gpio.h" 42 43 #include <sys/param.h> 44 #include <sys/device.h> 45 #include <sys/systm.h> 46 #include <sys/mutex.h> 47 #include <sys/bus.h> 48 #include <sys/intr.h> 49 #include <sys/kernel.h> 50 #include <sys/gpio.h> 51 #include <dev/gpio/gpiovar.h> 52 53 #include <sys/bitops.h> 54 55 #include <arm/broadcom/bcm_amba.h> 56 #include <arm/broadcom/bcm2835reg.h> 57 #include <arm/broadcom/bcm2835_gpioreg.h> 58 #include <arm/broadcom/bcm2835_gpio_subr.h> 59 60 /* #define BCM2835_GPIO_DEBUG */ 61 #ifdef BCM2835_GPIO_DEBUG 62 int bcm2835gpiodebug = 3; 63 #define DPRINTF(l, x) do { if (l <= bcm2835gpiodebug) { printf x; } } while (0) 64 #else 65 #define DPRINTF(l, x) 66 #endif 67 68 struct bcmgpio_softc { 69 device_t sc_dev; 70 bus_space_tag_t sc_iot; 71 bus_space_handle_t sc_ioh; 72 struct gpio_chipset_tag sc_gpio_gc; 73 gpio_pin_t sc_gpio_pins[32]; 74 }; 75 76 static int bcmgpio_match(device_t, cfdata_t, void *); 77 static void bcmgpio_attach(device_t, device_t, void *); 78 79 #if NGPIO > 0 80 static int bcm2835gpio_gpio_pin_read(void *, int); 81 static void bcm2835gpio_gpio_pin_write(void *, int, int); 82 static void bcm2835gpio_gpio_pin_ctl(void *, int, int); 83 #endif 84 85 CFATTACH_DECL_NEW(bcmgpio, sizeof(struct bcmgpio_softc), 86 bcmgpio_match, bcmgpio_attach, NULL, NULL); 87 88 static int 89 bcmgpio_match(device_t parent, cfdata_t cf, void *aux) 90 { 91 struct amba_attach_args * const aaa = aux; 92 93 if (strcmp(aaa->aaa_name, "bcmgpio") != 0) 94 return 0; 95 96 return 1; 97 } 98 99 static void 100 bcmgpio_attach(device_t parent, device_t self, void *aux) 101 { 102 struct bcmgpio_softc * const sc = device_private(self); 103 #if NGPIO > 0 104 struct amba_attach_args *aaa = aux; 105 struct gpiobus_attach_args gba; 106 int pin, minpin, maxpin; 107 u_int func; 108 int error; 109 #endif 110 111 sc->sc_dev = self; 112 113 #if NGPIO > 0 114 if (device_unit(sc->sc_dev) > 1) { 115 aprint_naive(" NO GPIO\n"); 116 aprint_normal(": NO GPIO\n"); 117 return; 118 } else if (device_unit(sc->sc_dev) == 1) { 119 maxpin = 53; 120 minpin = 32; 121 } else { 122 maxpin = 31; 123 minpin = 0; 124 } 125 126 aprint_naive("\n"); 127 aprint_normal(": GPIO [%d...%d]\n", minpin, maxpin); 128 129 sc->sc_iot = aaa->aaa_iot; 130 error = bus_space_map(sc->sc_iot, aaa->aaa_addr, aaa->aaa_size, 0, 131 &sc->sc_ioh); 132 if (error) { 133 aprint_error_dev(self, 134 "can't map registers for %s: %d\n", aaa->aaa_name, error); 135 return; 136 } 137 138 for (pin = minpin; pin <= maxpin; pin++) { 139 int epin = pin - minpin; 140 141 sc->sc_gpio_pins[epin].pin_num = epin; 142 /* 143 * find out pins still available for GPIO 144 */ 145 func = bcm2835gpio_function_read(pin); 146 147 if (func == BCM2835_GPIO_IN || 148 func == BCM2835_GPIO_OUT) { 149 sc->sc_gpio_pins[epin].pin_caps = GPIO_PIN_INPUT | 150 GPIO_PIN_OUTPUT | 151 GPIO_PIN_PUSHPULL | GPIO_PIN_TRISTATE | 152 GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN; 153 /* read initial state */ 154 sc->sc_gpio_pins[epin].pin_state = 155 bcm2835gpio_gpio_pin_read(sc, epin); 156 DPRINTF(1, ("%s: attach pin %d\n", device_xname(sc->sc_dev), pin)); 157 } else { 158 sc->sc_gpio_pins[epin].pin_caps = 0; 159 sc->sc_gpio_pins[epin].pin_state = 0; 160 DPRINTF(1, ("%s: skip pin %d - func = 0x%x\n", device_xname(sc->sc_dev), pin, func)); 161 } 162 } 163 164 /* create controller tag */ 165 sc->sc_gpio_gc.gp_cookie = sc; 166 sc->sc_gpio_gc.gp_pin_read = bcm2835gpio_gpio_pin_read; 167 sc->sc_gpio_gc.gp_pin_write = bcm2835gpio_gpio_pin_write; 168 sc->sc_gpio_gc.gp_pin_ctl = bcm2835gpio_gpio_pin_ctl; 169 170 gba.gba_gc = &sc->sc_gpio_gc; 171 gba.gba_pins = sc->sc_gpio_pins; 172 gba.gba_npins = maxpin - minpin + 1; 173 174 config_found_ia(self, "gpiobus", &gba, gpiobus_print); 175 #else 176 aprint_normal_dev(sc->sc_dev, "no GPIO configured in kernel"); 177 #endif 178 } 179 180 #if NGPIO > 0 181 /* GPIO support functions */ 182 static int 183 bcm2835gpio_gpio_pin_read(void *arg, int pin) 184 { 185 struct bcmgpio_softc *sc = arg; 186 int epin = pin + device_unit(sc->sc_dev) * 32; 187 uint32_t val; 188 int res; 189 190 if (device_unit(sc->sc_dev) > 1) { 191 return 0; 192 } 193 194 val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, 195 BCM2835_GPIO_GPLEV(epin / BCM2835_GPIO_GPLEV_PINS_PER_REGISTER)); 196 197 res = val & (1 << (epin % BCM2835_GPIO_GPLEV_PINS_PER_REGISTER)) ? 198 GPIO_PIN_HIGH : GPIO_PIN_LOW; 199 200 DPRINTF(2, ("%s: gpio_read pin %d->%d\n", device_xname(sc->sc_dev), epin, (res == GPIO_PIN_HIGH))); 201 202 return res; 203 } 204 205 static void 206 bcm2835gpio_gpio_pin_write(void *arg, int pin, int value) 207 { 208 struct bcmgpio_softc *sc = arg; 209 int epin = pin + device_unit(sc->sc_dev) * 32; 210 bus_size_t reg; 211 212 if (device_unit(sc->sc_dev) > 1) { 213 return; 214 } 215 216 if (value == GPIO_PIN_HIGH) { 217 reg = BCM2835_GPIO_GPSET(epin / BCM2835_GPIO_GPSET_PINS_PER_REGISTER); 218 } else { 219 reg = BCM2835_GPIO_GPCLR(epin / BCM2835_GPIO_GPCLR_PINS_PER_REGISTER); 220 } 221 222 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 223 reg, 1 << (epin % BCM2835_GPIO_GPSET_PINS_PER_REGISTER)); 224 DPRINTF(2, ("%s: gpio_write pin %d<-%d\n", device_xname(sc->sc_dev), epin, (value == GPIO_PIN_HIGH))); 225 } 226 227 static void 228 bcm2835gpio_gpio_pin_ctl(void *arg, int pin, int flags) 229 { 230 struct bcmgpio_softc *sc = arg; 231 uint32_t cmd; 232 int epin = pin + device_unit(sc->sc_dev) * 32; 233 234 if (device_unit(sc->sc_dev) > 1) { 235 return; 236 } 237 238 DPRINTF(2, ("%s: gpio_ctl pin %d flags 0x%x\n", device_xname(sc->sc_dev), epin, flags)); 239 240 if (flags & (GPIO_PIN_OUTPUT|GPIO_PIN_INPUT)) { 241 if ((flags & GPIO_PIN_INPUT) || !(flags & GPIO_PIN_OUTPUT)) { 242 /* for safety INPUT will overide output */ 243 bcm2835gpio_function_select(epin, BCM2835_GPIO_IN); 244 } else { 245 bcm2835gpio_function_select(epin, BCM2835_GPIO_OUT); 246 } 247 } 248 249 if (flags & (GPIO_PIN_PULLUP|GPIO_PIN_PULLDOWN)) { 250 cmd = (flags & GPIO_PIN_PULLUP) ? 251 BCM2835_GPIO_GPPUD_PULLUP : BCM2835_GPIO_GPPUD_PULLDOWN; 252 } else { 253 cmd = BCM2835_GPIO_GPPUD_PULLOFF; 254 } 255 256 /* set up control signal */ 257 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 258 BCM2835_GPIO_GPPUD, cmd); 259 delay(1); /* wait 150 cycles */ 260 /* set clock signal */ 261 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 262 BCM2835_GPIO_GPPUDCLK(device_unit(sc->sc_dev)), 263 1 << (epin % BCM2835_GPIO_GPPUD_PINS_PER_REGISTER)); 264 delay(1); /* wait 150 cycles */ 265 /* reset control signal and clock */ 266 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 267 BCM2835_GPIO_GPPUD, BCM2835_GPIO_GPPUD_PULLOFF); 268 bus_space_write_4(sc->sc_iot, sc->sc_ioh, 269 BCM2835_GPIO_GPPUDCLK(device_unit(sc->sc_dev)), 270 0); 271 } 272 #endif /* NGPIO > 0 */ 273