1/*- 2 * Copyright (c) 2011, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28/* 29 * GPIO driver for Cavium Octeon 30 */ 31 32#include <sys/cdefs.h>
| 1/*- 2 * Copyright (c) 2011, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 */ 27 28/* 29 * GPIO driver for Cavium Octeon 30 */ 31 32#include <sys/cdefs.h>
|
33__FBSDID("$FreeBSD: head/sys/mips/cavium/octeon_gpio.c 277968 2015-01-31 12:17:07Z loos $");
| 33__FBSDID("$FreeBSD: head/sys/mips/cavium/octeon_gpio.c 277996 2015-01-31 19:32:14Z loos $");
|
34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/bus.h> 38 39#include <sys/kernel.h> 40#include <sys/module.h> 41#include <sys/rman.h> 42#include <sys/lock.h> 43#include <sys/mutex.h> 44#include <sys/gpio.h> 45 46#include <machine/bus.h> 47#include <machine/resource.h> 48 49#include <contrib/octeon-sdk/cvmx.h> 50#include <contrib/octeon-sdk/cvmx-gpio.h> 51#include <mips/cavium/octeon_irq.h> 52 53#include <mips/cavium/octeon_gpiovar.h>
| 34 35#include <sys/param.h> 36#include <sys/systm.h> 37#include <sys/bus.h> 38 39#include <sys/kernel.h> 40#include <sys/module.h> 41#include <sys/rman.h> 42#include <sys/lock.h> 43#include <sys/mutex.h> 44#include <sys/gpio.h> 45 46#include <machine/bus.h> 47#include <machine/resource.h> 48 49#include <contrib/octeon-sdk/cvmx.h> 50#include <contrib/octeon-sdk/cvmx-gpio.h> 51#include <mips/cavium/octeon_irq.h> 52 53#include <mips/cavium/octeon_gpiovar.h>
|
| 54#include <dev/gpio/gpiobusvar.h>
|
54 55#include "gpio_if.h" 56 57#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 58 59struct octeon_gpio_pin { 60 const char *name; 61 int pin; 62 int flags; 63}; 64 65/* 66 * on CAP100 GPIO 7 is "Factory defaults" button 67 * 68 */ 69static struct octeon_gpio_pin octeon_gpio_pins[] = { 70 { "F/D", 7, GPIO_PIN_INPUT}, 71 { NULL, 0, 0}, 72}; 73 74/* 75 * Helpers 76 */ 77static void octeon_gpio_pin_configure(struct octeon_gpio_softc *sc, 78 struct gpio_pin *pin, uint32_t flags); 79 80/* 81 * Driver stuff 82 */ 83static void octeon_gpio_identify(driver_t *, device_t); 84static int octeon_gpio_probe(device_t dev); 85static int octeon_gpio_attach(device_t dev); 86static int octeon_gpio_detach(device_t dev); 87static int octeon_gpio_filter(void *arg); 88static void octeon_gpio_intr(void *arg); 89 90/* 91 * GPIO interface 92 */
| 55 56#include "gpio_if.h" 57 58#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) 59 60struct octeon_gpio_pin { 61 const char *name; 62 int pin; 63 int flags; 64}; 65 66/* 67 * on CAP100 GPIO 7 is "Factory defaults" button 68 * 69 */ 70static struct octeon_gpio_pin octeon_gpio_pins[] = { 71 { "F/D", 7, GPIO_PIN_INPUT}, 72 { NULL, 0, 0}, 73}; 74 75/* 76 * Helpers 77 */ 78static void octeon_gpio_pin_configure(struct octeon_gpio_softc *sc, 79 struct gpio_pin *pin, uint32_t flags); 80 81/* 82 * Driver stuff 83 */ 84static void octeon_gpio_identify(driver_t *, device_t); 85static int octeon_gpio_probe(device_t dev); 86static int octeon_gpio_attach(device_t dev); 87static int octeon_gpio_detach(device_t dev); 88static int octeon_gpio_filter(void *arg); 89static void octeon_gpio_intr(void *arg); 90 91/* 92 * GPIO interface 93 */
|
| 94static device_t octeon_gpio_get_bus(device_t);
|
93static int octeon_gpio_pin_max(device_t dev, int *maxpin); 94static int octeon_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); 95static int octeon_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t 96 *flags); 97static int octeon_gpio_pin_getname(device_t dev, uint32_t pin, char *name); 98static int octeon_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); 99static int octeon_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); 100static int octeon_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); 101static int octeon_gpio_pin_toggle(device_t dev, uint32_t pin); 102 103static void 104octeon_gpio_pin_configure(struct octeon_gpio_softc *sc, struct gpio_pin *pin, 105 unsigned int flags) 106{ 107 uint32_t mask; 108 cvmx_gpio_bit_cfgx_t gpio_cfgx; 109 110 mask = 1 << pin->gp_pin; 111 GPIO_LOCK(sc); 112 113 /* 114 * Manage input/output 115 */ 116 if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 117 gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(pin->gp_pin)); 118 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 119 if (flags & GPIO_PIN_OUTPUT) { 120 pin->gp_flags |= GPIO_PIN_OUTPUT; 121 gpio_cfgx.s.tx_oe = 1; 122 } 123 else { 124 pin->gp_flags |= GPIO_PIN_INPUT; 125 gpio_cfgx.s.tx_oe = 0; 126 } 127 if (flags & GPIO_PIN_INVIN) 128 gpio_cfgx.s.rx_xor = 1; 129 else 130 gpio_cfgx.s.rx_xor = 0; 131 cvmx_write_csr(CVMX_GPIO_BIT_CFGX(pin->gp_pin), gpio_cfgx.u64); 132 } 133 134 GPIO_UNLOCK(sc); 135} 136
| 95static int octeon_gpio_pin_max(device_t dev, int *maxpin); 96static int octeon_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); 97static int octeon_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t 98 *flags); 99static int octeon_gpio_pin_getname(device_t dev, uint32_t pin, char *name); 100static int octeon_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); 101static int octeon_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); 102static int octeon_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); 103static int octeon_gpio_pin_toggle(device_t dev, uint32_t pin); 104 105static void 106octeon_gpio_pin_configure(struct octeon_gpio_softc *sc, struct gpio_pin *pin, 107 unsigned int flags) 108{ 109 uint32_t mask; 110 cvmx_gpio_bit_cfgx_t gpio_cfgx; 111 112 mask = 1 << pin->gp_pin; 113 GPIO_LOCK(sc); 114 115 /* 116 * Manage input/output 117 */ 118 if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 119 gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(pin->gp_pin)); 120 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 121 if (flags & GPIO_PIN_OUTPUT) { 122 pin->gp_flags |= GPIO_PIN_OUTPUT; 123 gpio_cfgx.s.tx_oe = 1; 124 } 125 else { 126 pin->gp_flags |= GPIO_PIN_INPUT; 127 gpio_cfgx.s.tx_oe = 0; 128 } 129 if (flags & GPIO_PIN_INVIN) 130 gpio_cfgx.s.rx_xor = 1; 131 else 132 gpio_cfgx.s.rx_xor = 0; 133 cvmx_write_csr(CVMX_GPIO_BIT_CFGX(pin->gp_pin), gpio_cfgx.u64); 134 } 135 136 GPIO_UNLOCK(sc); 137} 138
|
| 139static device_t 140octeon_gpio_get_bus(device_t dev) 141{ 142 struct octeon_gpio_softc *sc; 143 144 sc = device_get_softc(dev); 145 146 return (sc->busdev); 147} 148
|
137static int 138octeon_gpio_pin_max(device_t dev, int *maxpin) 139{ 140 141 *maxpin = OCTEON_GPIO_PINS - 1; 142 return (0); 143} 144 145static int 146octeon_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 147{ 148 struct octeon_gpio_softc *sc = device_get_softc(dev); 149 int i; 150 151 for (i = 0; i < sc->gpio_npins; i++) { 152 if (sc->gpio_pins[i].gp_pin == pin) 153 break; 154 } 155 156 if (i >= sc->gpio_npins) 157 return (EINVAL); 158 159 GPIO_LOCK(sc); 160 *caps = sc->gpio_pins[i].gp_caps; 161 GPIO_UNLOCK(sc); 162 163 return (0); 164} 165 166static int 167octeon_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 168{ 169 struct octeon_gpio_softc *sc = device_get_softc(dev); 170 int i; 171 172 for (i = 0; i < sc->gpio_npins; i++) { 173 if (sc->gpio_pins[i].gp_pin == pin) 174 break; 175 } 176 177 if (i >= sc->gpio_npins) 178 return (EINVAL); 179 180 GPIO_LOCK(sc); 181 *flags = sc->gpio_pins[i].gp_flags; 182 GPIO_UNLOCK(sc); 183 184 return (0); 185} 186 187static int 188octeon_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 189{ 190 struct octeon_gpio_softc *sc = device_get_softc(dev); 191 int i; 192 193 for (i = 0; i < sc->gpio_npins; i++) { 194 if (sc->gpio_pins[i].gp_pin == pin) 195 break; 196 } 197 198 if (i >= sc->gpio_npins) 199 return (EINVAL); 200 201 GPIO_LOCK(sc); 202 memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 203 GPIO_UNLOCK(sc); 204 205 return (0); 206} 207 208static int 209octeon_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 210{ 211 int i; 212 struct octeon_gpio_softc *sc = device_get_softc(dev); 213 214 for (i = 0; i < sc->gpio_npins; i++) { 215 if (sc->gpio_pins[i].gp_pin == pin) 216 break; 217 } 218 219 if (i >= sc->gpio_npins) 220 return (EINVAL); 221 222 octeon_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 223 224 return (0); 225} 226 227static int 228octeon_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 229{ 230 struct octeon_gpio_softc *sc = device_get_softc(dev); 231 int i; 232 233 for (i = 0; i < sc->gpio_npins; i++) { 234 if (sc->gpio_pins[i].gp_pin == pin) 235 break; 236 } 237 238 if (i >= sc->gpio_npins) 239 return (EINVAL); 240 241 GPIO_LOCK(sc); 242 if (value) 243 cvmx_gpio_set(1 << pin); 244 else 245 cvmx_gpio_clear(1 << pin); 246 GPIO_UNLOCK(sc); 247 248 return (0); 249} 250 251static int 252octeon_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 253{ 254 struct octeon_gpio_softc *sc = device_get_softc(dev); 255 int i; 256 uint64_t state; 257 258 for (i = 0; i < sc->gpio_npins; i++) { 259 if (sc->gpio_pins[i].gp_pin == pin) 260 break; 261 } 262 263 if (i >= sc->gpio_npins) 264 return (EINVAL); 265 266 GPIO_LOCK(sc); 267 state = cvmx_gpio_read(); 268 *val = (state & (1 << pin)) ? 1 : 0; 269 GPIO_UNLOCK(sc); 270 271 return (0); 272} 273 274static int 275octeon_gpio_pin_toggle(device_t dev, uint32_t pin) 276{ 277 int i; 278 uint64_t state; 279 struct octeon_gpio_softc *sc = device_get_softc(dev); 280 281 for (i = 0; i < sc->gpio_npins; i++) { 282 if (sc->gpio_pins[i].gp_pin == pin) 283 break; 284 } 285 286 if (i >= sc->gpio_npins) 287 return (EINVAL); 288 289 GPIO_LOCK(sc); 290 /* 291 * XXX: Need to check if read returns actual state of output 292 * pins or we need to keep this information by ourself 293 */ 294 state = cvmx_gpio_read(); 295 if (state & (1 << pin)) 296 cvmx_gpio_clear(1 << pin); 297 else 298 cvmx_gpio_set(1 << pin); 299 GPIO_UNLOCK(sc); 300 301 return (0); 302} 303 304static int 305octeon_gpio_filter(void *arg) 306{ 307 cvmx_gpio_bit_cfgx_t gpio_cfgx; 308 void **cookie = arg; 309 struct octeon_gpio_softc *sc = *cookie; 310 long int irq = (cookie - sc->gpio_intr_cookies); 311 312 if ((irq < 0) || (irq >= OCTEON_GPIO_IRQS)) 313 return (FILTER_STRAY); 314 315 gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(irq)); 316 /* Clear rising edge detector */ 317 if (gpio_cfgx.s.int_type == OCTEON_GPIO_IRQ_EDGE) 318 cvmx_gpio_interrupt_clear(1 << irq); 319 /* disable interrupt */ 320 gpio_cfgx.s.int_en = 0; 321 cvmx_write_csr(CVMX_GPIO_BIT_CFGX(irq), gpio_cfgx.u64); 322 323 return (FILTER_SCHEDULE_THREAD); 324} 325 326static void 327octeon_gpio_intr(void *arg) 328{ 329 cvmx_gpio_bit_cfgx_t gpio_cfgx; 330 void **cookie = arg; 331 struct octeon_gpio_softc *sc = *cookie; 332 long int irq = (cookie - sc->gpio_intr_cookies); 333 334 if ((irq < 0) || (irq >= OCTEON_GPIO_IRQS)) { 335 printf("%s: invalid GPIO IRQ: %ld\n", 336 __func__, irq); 337 return; 338 } 339 340 GPIO_LOCK(sc); 341 gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(irq)); 342 /* disable interrupt */ 343 gpio_cfgx.s.int_en = 1; 344 cvmx_write_csr(CVMX_GPIO_BIT_CFGX(irq), gpio_cfgx.u64); 345 346 /* TODO: notify bus here or something */ 347 printf("GPIO IRQ for pin %ld\n", irq); 348 GPIO_UNLOCK(sc); 349} 350 351static void 352octeon_gpio_identify(driver_t *drv, device_t parent) 353{ 354 355 BUS_ADD_CHILD(parent, 0, "gpio", 0); 356} 357 358static int 359octeon_gpio_probe(device_t dev) 360{ 361 362 device_set_desc(dev, "Cavium Octeon GPIO driver"); 363 return (0); 364} 365 366static int 367octeon_gpio_attach(device_t dev) 368{ 369 struct octeon_gpio_softc *sc = device_get_softc(dev); 370 struct octeon_gpio_pin *pinp; 371 cvmx_gpio_bit_cfgx_t gpio_cfgx; 372 373 int i; 374 375 KASSERT((device_get_unit(dev) == 0), 376 ("octeon_gpio: Only one gpio module supported")); 377 378 mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 379 380 for ( i = 0; i < OCTEON_GPIO_IRQS; i++) { 381 if ((sc->gpio_irq_res[i] = bus_alloc_resource(dev, 382 SYS_RES_IRQ, &sc->gpio_irq_rid[i], 383 OCTEON_IRQ_GPIO0 + i, OCTEON_IRQ_GPIO0 + i, 1, 384 RF_SHAREABLE | RF_ACTIVE)) == NULL) { 385 device_printf(dev, "unable to allocate IRQ resource\n"); 386 octeon_gpio_detach(dev); 387 return (ENXIO); 388 } 389 390 sc->gpio_intr_cookies[i] = sc; 391 if ((bus_setup_intr(dev, sc->gpio_irq_res[i], INTR_TYPE_MISC, 392 octeon_gpio_filter, octeon_gpio_intr, 393 &(sc->gpio_intr_cookies[i]), &sc->gpio_ih[i]))) { 394 device_printf(dev, 395 "WARNING: unable to register interrupt handler\n"); 396 octeon_gpio_detach(dev); 397 return (ENXIO); 398 } 399 } 400 401 sc->dev = dev; 402 /* Configure all pins as input */ 403 /* disable interrupts for all pins */ 404 pinp = octeon_gpio_pins; 405 i = 0; 406 while (pinp->name) { 407 strncpy(sc->gpio_pins[i].gp_name, pinp->name, GPIOMAXNAME); 408 sc->gpio_pins[i].gp_pin = pinp->pin; 409 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 410 sc->gpio_pins[i].gp_flags = 0; 411 octeon_gpio_pin_configure(sc, &sc->gpio_pins[i], pinp->flags); 412 pinp++; 413 i++; 414 } 415 416 sc->gpio_npins = i; 417 418#if 0 419 /* 420 * Sample: how to enable edge-triggered interrupt 421 * for GPIO pin 422 */ 423 gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(7)); 424 gpio_cfgx.s.int_en = 1; 425 gpio_cfgx.s.int_type = OCTEON_GPIO_IRQ_EDGE; 426 cvmx_write_csr(CVMX_GPIO_BIT_CFGX(7), gpio_cfgx.u64); 427#endif 428 429 if (bootverbose) { 430 for (i = 0; i < 16; i++) { 431 gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(i)); 432 device_printf(dev, "[pin%d] output=%d, invinput=%d, intr=%d, intr_type=%s\n", 433 i, gpio_cfgx.s.tx_oe, gpio_cfgx.s.rx_xor, 434 gpio_cfgx.s.int_en, gpio_cfgx.s.int_type ? "rising edge" : "level"); 435 } 436 }
| 149static int 150octeon_gpio_pin_max(device_t dev, int *maxpin) 151{ 152 153 *maxpin = OCTEON_GPIO_PINS - 1; 154 return (0); 155} 156 157static int 158octeon_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 159{ 160 struct octeon_gpio_softc *sc = device_get_softc(dev); 161 int i; 162 163 for (i = 0; i < sc->gpio_npins; i++) { 164 if (sc->gpio_pins[i].gp_pin == pin) 165 break; 166 } 167 168 if (i >= sc->gpio_npins) 169 return (EINVAL); 170 171 GPIO_LOCK(sc); 172 *caps = sc->gpio_pins[i].gp_caps; 173 GPIO_UNLOCK(sc); 174 175 return (0); 176} 177 178static int 179octeon_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 180{ 181 struct octeon_gpio_softc *sc = device_get_softc(dev); 182 int i; 183 184 for (i = 0; i < sc->gpio_npins; i++) { 185 if (sc->gpio_pins[i].gp_pin == pin) 186 break; 187 } 188 189 if (i >= sc->gpio_npins) 190 return (EINVAL); 191 192 GPIO_LOCK(sc); 193 *flags = sc->gpio_pins[i].gp_flags; 194 GPIO_UNLOCK(sc); 195 196 return (0); 197} 198 199static int 200octeon_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 201{ 202 struct octeon_gpio_softc *sc = device_get_softc(dev); 203 int i; 204 205 for (i = 0; i < sc->gpio_npins; i++) { 206 if (sc->gpio_pins[i].gp_pin == pin) 207 break; 208 } 209 210 if (i >= sc->gpio_npins) 211 return (EINVAL); 212 213 GPIO_LOCK(sc); 214 memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 215 GPIO_UNLOCK(sc); 216 217 return (0); 218} 219 220static int 221octeon_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 222{ 223 int i; 224 struct octeon_gpio_softc *sc = device_get_softc(dev); 225 226 for (i = 0; i < sc->gpio_npins; i++) { 227 if (sc->gpio_pins[i].gp_pin == pin) 228 break; 229 } 230 231 if (i >= sc->gpio_npins) 232 return (EINVAL); 233 234 octeon_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 235 236 return (0); 237} 238 239static int 240octeon_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 241{ 242 struct octeon_gpio_softc *sc = device_get_softc(dev); 243 int i; 244 245 for (i = 0; i < sc->gpio_npins; i++) { 246 if (sc->gpio_pins[i].gp_pin == pin) 247 break; 248 } 249 250 if (i >= sc->gpio_npins) 251 return (EINVAL); 252 253 GPIO_LOCK(sc); 254 if (value) 255 cvmx_gpio_set(1 << pin); 256 else 257 cvmx_gpio_clear(1 << pin); 258 GPIO_UNLOCK(sc); 259 260 return (0); 261} 262 263static int 264octeon_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 265{ 266 struct octeon_gpio_softc *sc = device_get_softc(dev); 267 int i; 268 uint64_t state; 269 270 for (i = 0; i < sc->gpio_npins; i++) { 271 if (sc->gpio_pins[i].gp_pin == pin) 272 break; 273 } 274 275 if (i >= sc->gpio_npins) 276 return (EINVAL); 277 278 GPIO_LOCK(sc); 279 state = cvmx_gpio_read(); 280 *val = (state & (1 << pin)) ? 1 : 0; 281 GPIO_UNLOCK(sc); 282 283 return (0); 284} 285 286static int 287octeon_gpio_pin_toggle(device_t dev, uint32_t pin) 288{ 289 int i; 290 uint64_t state; 291 struct octeon_gpio_softc *sc = device_get_softc(dev); 292 293 for (i = 0; i < sc->gpio_npins; i++) { 294 if (sc->gpio_pins[i].gp_pin == pin) 295 break; 296 } 297 298 if (i >= sc->gpio_npins) 299 return (EINVAL); 300 301 GPIO_LOCK(sc); 302 /* 303 * XXX: Need to check if read returns actual state of output 304 * pins or we need to keep this information by ourself 305 */ 306 state = cvmx_gpio_read(); 307 if (state & (1 << pin)) 308 cvmx_gpio_clear(1 << pin); 309 else 310 cvmx_gpio_set(1 << pin); 311 GPIO_UNLOCK(sc); 312 313 return (0); 314} 315 316static int 317octeon_gpio_filter(void *arg) 318{ 319 cvmx_gpio_bit_cfgx_t gpio_cfgx; 320 void **cookie = arg; 321 struct octeon_gpio_softc *sc = *cookie; 322 long int irq = (cookie - sc->gpio_intr_cookies); 323 324 if ((irq < 0) || (irq >= OCTEON_GPIO_IRQS)) 325 return (FILTER_STRAY); 326 327 gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(irq)); 328 /* Clear rising edge detector */ 329 if (gpio_cfgx.s.int_type == OCTEON_GPIO_IRQ_EDGE) 330 cvmx_gpio_interrupt_clear(1 << irq); 331 /* disable interrupt */ 332 gpio_cfgx.s.int_en = 0; 333 cvmx_write_csr(CVMX_GPIO_BIT_CFGX(irq), gpio_cfgx.u64); 334 335 return (FILTER_SCHEDULE_THREAD); 336} 337 338static void 339octeon_gpio_intr(void *arg) 340{ 341 cvmx_gpio_bit_cfgx_t gpio_cfgx; 342 void **cookie = arg; 343 struct octeon_gpio_softc *sc = *cookie; 344 long int irq = (cookie - sc->gpio_intr_cookies); 345 346 if ((irq < 0) || (irq >= OCTEON_GPIO_IRQS)) { 347 printf("%s: invalid GPIO IRQ: %ld\n", 348 __func__, irq); 349 return; 350 } 351 352 GPIO_LOCK(sc); 353 gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(irq)); 354 /* disable interrupt */ 355 gpio_cfgx.s.int_en = 1; 356 cvmx_write_csr(CVMX_GPIO_BIT_CFGX(irq), gpio_cfgx.u64); 357 358 /* TODO: notify bus here or something */ 359 printf("GPIO IRQ for pin %ld\n", irq); 360 GPIO_UNLOCK(sc); 361} 362 363static void 364octeon_gpio_identify(driver_t *drv, device_t parent) 365{ 366 367 BUS_ADD_CHILD(parent, 0, "gpio", 0); 368} 369 370static int 371octeon_gpio_probe(device_t dev) 372{ 373 374 device_set_desc(dev, "Cavium Octeon GPIO driver"); 375 return (0); 376} 377 378static int 379octeon_gpio_attach(device_t dev) 380{ 381 struct octeon_gpio_softc *sc = device_get_softc(dev); 382 struct octeon_gpio_pin *pinp; 383 cvmx_gpio_bit_cfgx_t gpio_cfgx; 384 385 int i; 386 387 KASSERT((device_get_unit(dev) == 0), 388 ("octeon_gpio: Only one gpio module supported")); 389 390 mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 391 392 for ( i = 0; i < OCTEON_GPIO_IRQS; i++) { 393 if ((sc->gpio_irq_res[i] = bus_alloc_resource(dev, 394 SYS_RES_IRQ, &sc->gpio_irq_rid[i], 395 OCTEON_IRQ_GPIO0 + i, OCTEON_IRQ_GPIO0 + i, 1, 396 RF_SHAREABLE | RF_ACTIVE)) == NULL) { 397 device_printf(dev, "unable to allocate IRQ resource\n"); 398 octeon_gpio_detach(dev); 399 return (ENXIO); 400 } 401 402 sc->gpio_intr_cookies[i] = sc; 403 if ((bus_setup_intr(dev, sc->gpio_irq_res[i], INTR_TYPE_MISC, 404 octeon_gpio_filter, octeon_gpio_intr, 405 &(sc->gpio_intr_cookies[i]), &sc->gpio_ih[i]))) { 406 device_printf(dev, 407 "WARNING: unable to register interrupt handler\n"); 408 octeon_gpio_detach(dev); 409 return (ENXIO); 410 } 411 } 412 413 sc->dev = dev; 414 /* Configure all pins as input */ 415 /* disable interrupts for all pins */ 416 pinp = octeon_gpio_pins; 417 i = 0; 418 while (pinp->name) { 419 strncpy(sc->gpio_pins[i].gp_name, pinp->name, GPIOMAXNAME); 420 sc->gpio_pins[i].gp_pin = pinp->pin; 421 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 422 sc->gpio_pins[i].gp_flags = 0; 423 octeon_gpio_pin_configure(sc, &sc->gpio_pins[i], pinp->flags); 424 pinp++; 425 i++; 426 } 427 428 sc->gpio_npins = i; 429 430#if 0 431 /* 432 * Sample: how to enable edge-triggered interrupt 433 * for GPIO pin 434 */ 435 gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(7)); 436 gpio_cfgx.s.int_en = 1; 437 gpio_cfgx.s.int_type = OCTEON_GPIO_IRQ_EDGE; 438 cvmx_write_csr(CVMX_GPIO_BIT_CFGX(7), gpio_cfgx.u64); 439#endif 440 441 if (bootverbose) { 442 for (i = 0; i < 16; i++) { 443 gpio_cfgx.u64 = cvmx_read_csr(CVMX_GPIO_BIT_CFGX(i)); 444 device_printf(dev, "[pin%d] output=%d, invinput=%d, intr=%d, intr_type=%s\n", 445 i, gpio_cfgx.s.tx_oe, gpio_cfgx.s.rx_xor, 446 gpio_cfgx.s.int_en, gpio_cfgx.s.int_type ? "rising edge" : "level"); 447 } 448 }
|
| 449 sc->busdev = gpiobus_attach_bus(dev); 450 if (sc->busdev == NULL) { 451 octeon_gpio_detach(dev); 452 return (ENXIO); 453 }
|
437
| 454
|
438 device_add_child(dev, "gpioc", -1); 439 device_add_child(dev, "gpiobus", -1); 440 441 return (bus_generic_attach(dev));
| 455 return (0);
|
442} 443 444static int 445octeon_gpio_detach(device_t dev) 446{ 447 struct octeon_gpio_softc *sc = device_get_softc(dev); 448 int i; 449 450 KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized")); 451 452 for ( i = 0; i < OCTEON_GPIO_IRQS; i++) { 453 if (sc->gpio_ih[i]) 454 bus_teardown_intr(dev, sc->gpio_irq_res[i], 455 sc->gpio_ih[i]); 456 if (sc->gpio_irq_res[i]) 457 bus_release_resource(dev, SYS_RES_IRQ, 458 sc->gpio_irq_rid[i], sc->gpio_irq_res[i]); 459 }
| 456} 457 458static int 459octeon_gpio_detach(device_t dev) 460{ 461 struct octeon_gpio_softc *sc = device_get_softc(dev); 462 int i; 463 464 KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized")); 465 466 for ( i = 0; i < OCTEON_GPIO_IRQS; i++) { 467 if (sc->gpio_ih[i]) 468 bus_teardown_intr(dev, sc->gpio_irq_res[i], 469 sc->gpio_ih[i]); 470 if (sc->gpio_irq_res[i]) 471 bus_release_resource(dev, SYS_RES_IRQ, 472 sc->gpio_irq_rid[i], sc->gpio_irq_res[i]); 473 }
|
460 bus_generic_detach(dev);
| 474 gpiobus_detach_bus(dev);
|
461 mtx_destroy(&sc->gpio_mtx); 462 463 return(0); 464} 465 466static device_method_t octeon_gpio_methods[] = { 467 DEVMETHOD(device_identify, octeon_gpio_identify), 468 DEVMETHOD(device_probe, octeon_gpio_probe), 469 DEVMETHOD(device_attach, octeon_gpio_attach), 470 DEVMETHOD(device_detach, octeon_gpio_detach), 471 472 /* GPIO protocol */
| 475 mtx_destroy(&sc->gpio_mtx); 476 477 return(0); 478} 479 480static device_method_t octeon_gpio_methods[] = { 481 DEVMETHOD(device_identify, octeon_gpio_identify), 482 DEVMETHOD(device_probe, octeon_gpio_probe), 483 DEVMETHOD(device_attach, octeon_gpio_attach), 484 DEVMETHOD(device_detach, octeon_gpio_detach), 485 486 /* GPIO protocol */
|
| 487 DEVMETHOD(gpio_get_bus, octeon_gpio_get_bus),
|
473 DEVMETHOD(gpio_pin_max, octeon_gpio_pin_max), 474 DEVMETHOD(gpio_pin_getname, octeon_gpio_pin_getname), 475 DEVMETHOD(gpio_pin_getflags, octeon_gpio_pin_getflags), 476 DEVMETHOD(gpio_pin_getcaps, octeon_gpio_pin_getcaps), 477 DEVMETHOD(gpio_pin_setflags, octeon_gpio_pin_setflags), 478 DEVMETHOD(gpio_pin_get, octeon_gpio_pin_get), 479 DEVMETHOD(gpio_pin_set, octeon_gpio_pin_set), 480 DEVMETHOD(gpio_pin_toggle, octeon_gpio_pin_toggle), 481 {0, 0}, 482}; 483 484static driver_t octeon_gpio_driver = { 485 "gpio", 486 octeon_gpio_methods, 487 sizeof(struct octeon_gpio_softc), 488}; 489static devclass_t octeon_gpio_devclass; 490 491DRIVER_MODULE(octeon_gpio, ciu, octeon_gpio_driver, octeon_gpio_devclass, 0, 0);
| 488 DEVMETHOD(gpio_pin_max, octeon_gpio_pin_max), 489 DEVMETHOD(gpio_pin_getname, octeon_gpio_pin_getname), 490 DEVMETHOD(gpio_pin_getflags, octeon_gpio_pin_getflags), 491 DEVMETHOD(gpio_pin_getcaps, octeon_gpio_pin_getcaps), 492 DEVMETHOD(gpio_pin_setflags, octeon_gpio_pin_setflags), 493 DEVMETHOD(gpio_pin_get, octeon_gpio_pin_get), 494 DEVMETHOD(gpio_pin_set, octeon_gpio_pin_set), 495 DEVMETHOD(gpio_pin_toggle, octeon_gpio_pin_toggle), 496 {0, 0}, 497}; 498 499static driver_t octeon_gpio_driver = { 500 "gpio", 501 octeon_gpio_methods, 502 sizeof(struct octeon_gpio_softc), 503}; 504static devclass_t octeon_gpio_devclass; 505 506DRIVER_MODULE(octeon_gpio, ciu, octeon_gpio_driver, octeon_gpio_devclass, 0, 0);
|