1215142Sthompsa/*- 2215142Sthompsa * Copyright (c) 2010, Andrew Thompson <thompsa@FreeBSD.org> 3215142Sthompsa * All rights reserved. 4215142Sthompsa * 5215142Sthompsa * Redistribution and use in source and binary forms, with or without 6215142Sthompsa * modification, are permitted provided that the following conditions 7215142Sthompsa * are met: 8215142Sthompsa * 1. Redistributions of source code must retain the above copyright 9215142Sthompsa * notice unmodified, this list of conditions, and the following 10215142Sthompsa * disclaimer. 11215142Sthompsa * 2. Redistributions in binary form must reproduce the above copyright 12215142Sthompsa * notice, this list of conditions and the following disclaimer in the 13215142Sthompsa * documentation and/or other materials provided with the distribution. 14215142Sthompsa * 15215142Sthompsa * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16215142Sthompsa * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17215142Sthompsa * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18215142Sthompsa * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19215142Sthompsa * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20215142Sthompsa * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21215142Sthompsa * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22215142Sthompsa * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23215142Sthompsa * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24215142Sthompsa * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25215142Sthompsa * SUCH DAMAGE. 26215142Sthompsa */ 27215142Sthompsa 28215142Sthompsa/* 29215142Sthompsa * GPIO driver for Gateworks Cambria 30215142Sthompsa * 31215142Sthompsa * Note: 32215142Sthompsa * The Cambria PLD does not set the i2c ack bit after each write, if we used the 33215142Sthompsa * regular iicbus interface it would abort the xfer after the address byte 34215142Sthompsa * times out and not write our latch. To get around this we grab the iicbus and 35215142Sthompsa * then do our own bit banging. This is a comprimise to changing all the iicbb 36215142Sthompsa * device methods to allow a flag to be passed down and is similir to how Linux 37215142Sthompsa * does it. 38215142Sthompsa * 39215142Sthompsa */ 40215142Sthompsa 41215142Sthompsa#include <sys/cdefs.h> 42215142Sthompsa__FBSDID("$FreeBSD$"); 43215142Sthompsa 44215142Sthompsa#include <sys/param.h> 45215142Sthompsa#include <sys/systm.h> 46215142Sthompsa#include <sys/bus.h> 47215142Sthompsa 48215142Sthompsa#include <sys/kernel.h> 49215142Sthompsa#include <sys/module.h> 50215142Sthompsa#include <sys/rman.h> 51215142Sthompsa#include <sys/lock.h> 52215142Sthompsa#include <sys/mutex.h> 53215142Sthompsa#include <sys/gpio.h> 54215142Sthompsa 55215142Sthompsa#include <arm/xscale/ixp425/ixp425reg.h> 56215142Sthompsa#include <arm/xscale/ixp425/ixp425var.h> 57215142Sthompsa#include <arm/xscale/ixp425/ixdp425reg.h> 58215142Sthompsa 59215142Sthompsa#include <dev/iicbus/iiconf.h> 60215142Sthompsa#include <dev/iicbus/iicbus.h> 61215142Sthompsa 62215142Sthompsa#include "iicbb_if.h" 63215142Sthompsa#include "gpio_if.h" 64215142Sthompsa 65215142Sthompsa#define IIC_M_WR 0 /* write operation */ 66215142Sthompsa#define PLD_ADDR 0xac /* slave address */ 67215142Sthompsa 68215142Sthompsa#define I2C_DELAY 10 69215142Sthompsa 70215142Sthompsa#define GPIO_CONF_CLR(sc, reg, mask) \ 71215142Sthompsa GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, reg) &~ (mask)) 72215142Sthompsa#define GPIO_CONF_SET(sc, reg, mask) \ 73215142Sthompsa GPIO_CONF_WRITE_4(sc, reg, GPIO_CONF_READ_4(sc, reg) | (mask)) 74215142Sthompsa 75215142Sthompsa#define GPIO_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) 76215142Sthompsa#define GPIO_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) 77215142Sthompsa#define GPIO_LOCK_ASSERT(_sc) mtx_assert(&(_sc)->sc_mtx, MA_OWNED) 78215142Sthompsa 79215142Sthompsa#define GPIO_PINS 5 80215142Sthompsastruct cambria_gpio_softc { 81215142Sthompsa device_t sc_dev; 82215142Sthompsa bus_space_tag_t sc_iot; 83215142Sthompsa bus_space_handle_t sc_gpio_ioh; 84215142Sthompsa struct mtx sc_mtx; 85215142Sthompsa struct gpio_pin sc_pins[GPIO_PINS]; 86215142Sthompsa uint8_t sc_latch; 87226324Sthompsa uint8_t sc_val; 88215142Sthompsa}; 89215142Sthompsa 90215142Sthompsastruct cambria_gpio_pin { 91215142Sthompsa const char *name; 92215142Sthompsa int pin; 93215142Sthompsa int flags; 94215142Sthompsa}; 95215142Sthompsa 96215142Sthompsaextern struct ixp425_softc *ixp425_softc; 97215142Sthompsa 98215142Sthompsastatic struct cambria_gpio_pin cambria_gpio_pins[GPIO_PINS] = { 99226325Sthompsa { "PLD0", 0, GPIO_PIN_OUTPUT }, 100226325Sthompsa { "PLD1", 1, GPIO_PIN_OUTPUT }, 101226325Sthompsa { "PLD2", 2, GPIO_PIN_OUTPUT }, 102226325Sthompsa { "PLD3", 3, GPIO_PIN_OUTPUT }, 103226325Sthompsa { "PLD4", 4, GPIO_PIN_OUTPUT }, 104215142Sthompsa}; 105215142Sthompsa 106215142Sthompsa/* 107215142Sthompsa * Helpers 108215142Sthompsa */ 109215142Sthompsastatic int cambria_gpio_read(struct cambria_gpio_softc *, uint32_t, unsigned int *); 110215142Sthompsastatic int cambria_gpio_write(struct cambria_gpio_softc *); 111215142Sthompsa 112215142Sthompsa/* 113215142Sthompsa * Driver stuff 114215142Sthompsa */ 115215142Sthompsastatic int cambria_gpio_probe(device_t dev); 116215142Sthompsastatic int cambria_gpio_attach(device_t dev); 117215142Sthompsastatic int cambria_gpio_detach(device_t dev); 118215142Sthompsa 119215142Sthompsa/* 120215142Sthompsa * GPIO interface 121215142Sthompsa */ 122215142Sthompsastatic int cambria_gpio_pin_max(device_t dev, int *maxpin); 123215142Sthompsastatic int cambria_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); 124215142Sthompsastatic int cambria_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t 125215142Sthompsa *flags); 126215142Sthompsastatic int cambria_gpio_pin_getname(device_t dev, uint32_t pin, char *name); 127215142Sthompsastatic int cambria_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); 128215142Sthompsastatic int cambria_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); 129215142Sthompsastatic int cambria_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); 130215142Sthompsastatic int cambria_gpio_pin_toggle(device_t dev, uint32_t pin); 131215142Sthompsa 132215142Sthompsastatic int 133215142Sthompsai2c_getsda(struct cambria_gpio_softc *sc) 134215142Sthompsa{ 135215142Sthompsa uint32_t reg; 136215142Sthompsa 137215319Sthompsa IXP4XX_GPIO_LOCK(); 138215142Sthompsa GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT); 139215142Sthompsa 140215142Sthompsa reg = GPIO_CONF_READ_4(sc, IXP425_GPIO_GPINR); 141215319Sthompsa IXP4XX_GPIO_UNLOCK(); 142215142Sthompsa return (reg & GPIO_I2C_SDA_BIT); 143215142Sthompsa} 144215142Sthompsa 145215142Sthompsastatic void 146215142Sthompsai2c_setsda(struct cambria_gpio_softc *sc, int val) 147215142Sthompsa{ 148215142Sthompsa 149215319Sthompsa IXP4XX_GPIO_LOCK(); 150215142Sthompsa GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, GPIO_I2C_SDA_BIT); 151215142Sthompsa if (val) 152215142Sthompsa GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT); 153215142Sthompsa else 154215142Sthompsa GPIO_CONF_CLR(sc, IXP425_GPIO_GPOER, GPIO_I2C_SDA_BIT); 155215319Sthompsa IXP4XX_GPIO_UNLOCK(); 156215142Sthompsa DELAY(I2C_DELAY); 157215142Sthompsa} 158215142Sthompsa 159215142Sthompsastatic void 160215142Sthompsai2c_setscl(struct cambria_gpio_softc *sc, int val) 161215142Sthompsa{ 162215142Sthompsa 163215319Sthompsa IXP4XX_GPIO_LOCK(); 164215142Sthompsa GPIO_CONF_CLR(sc, IXP425_GPIO_GPOUTR, GPIO_I2C_SCL_BIT); 165215142Sthompsa if (val) 166215142Sthompsa GPIO_CONF_SET(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT); 167215142Sthompsa else 168215142Sthompsa GPIO_CONF_CLR(sc, IXP425_GPIO_GPOER, GPIO_I2C_SCL_BIT); 169215319Sthompsa IXP4XX_GPIO_UNLOCK(); 170215142Sthompsa DELAY(I2C_DELAY); 171215142Sthompsa} 172215142Sthompsa 173215142Sthompsastatic void 174215142Sthompsai2c_sendstart(struct cambria_gpio_softc *sc) 175215142Sthompsa{ 176215142Sthompsa i2c_setsda(sc, 1); 177215142Sthompsa i2c_setscl(sc, 1); 178215142Sthompsa i2c_setsda(sc, 0); 179215142Sthompsa i2c_setscl(sc, 0); 180215142Sthompsa} 181215142Sthompsa 182215142Sthompsastatic void 183215142Sthompsai2c_sendstop(struct cambria_gpio_softc *sc) 184215142Sthompsa{ 185215142Sthompsa i2c_setscl(sc, 1); 186215142Sthompsa i2c_setsda(sc, 1); 187215142Sthompsa i2c_setscl(sc, 0); 188215142Sthompsa i2c_setsda(sc, 0); 189215142Sthompsa} 190215142Sthompsa 191215142Sthompsastatic void 192215142Sthompsai2c_sendbyte(struct cambria_gpio_softc *sc, u_char data) 193215142Sthompsa{ 194215142Sthompsa int i; 195215142Sthompsa 196215142Sthompsa for (i=7; i>=0; i--) { 197215142Sthompsa i2c_setsda(sc, data & (1<<i)); 198215142Sthompsa i2c_setscl(sc, 1); 199215142Sthompsa i2c_setscl(sc, 0); 200215142Sthompsa } 201215142Sthompsa i2c_setscl(sc, 1); 202215142Sthompsa i2c_getsda(sc); 203215142Sthompsa i2c_setscl(sc, 0); 204215142Sthompsa} 205215142Sthompsa 206215142Sthompsastatic u_char 207215142Sthompsai2c_readbyte(struct cambria_gpio_softc *sc) 208215142Sthompsa{ 209215142Sthompsa int i; 210215142Sthompsa unsigned char data=0; 211215142Sthompsa 212215142Sthompsa for (i=7; i>=0; i--) 213215142Sthompsa { 214215142Sthompsa i2c_setscl(sc, 1); 215215142Sthompsa if (i2c_getsda(sc)) 216215142Sthompsa data |= (1<<i); 217215142Sthompsa i2c_setscl(sc, 0); 218215142Sthompsa } 219215142Sthompsa return data; 220215142Sthompsa} 221215142Sthompsa 222215142Sthompsastatic int 223215142Sthompsacambria_gpio_read(struct cambria_gpio_softc *sc, uint32_t pin, unsigned int *val) 224215142Sthompsa{ 225215142Sthompsa device_t dev = sc->sc_dev; 226215142Sthompsa int error; 227215142Sthompsa 228215142Sthompsa error = iicbus_request_bus(device_get_parent(dev), dev, 229215142Sthompsa IIC_DONTWAIT); 230215142Sthompsa if (error) 231215142Sthompsa return (error); 232215142Sthompsa 233215142Sthompsa i2c_sendstart(sc); 234215142Sthompsa i2c_sendbyte(sc, PLD_ADDR | LSB); 235215142Sthompsa *val = (i2c_readbyte(sc) & (1 << pin)) != 0; 236215142Sthompsa i2c_sendstop(sc); 237215142Sthompsa 238215142Sthompsa iicbus_release_bus(device_get_parent(dev), dev); 239215142Sthompsa 240215142Sthompsa return (0); 241215142Sthompsa} 242215142Sthompsa 243215142Sthompsastatic int 244215142Sthompsacambria_gpio_write(struct cambria_gpio_softc *sc) 245215142Sthompsa{ 246215142Sthompsa device_t dev = sc->sc_dev; 247215142Sthompsa int error; 248215142Sthompsa 249215142Sthompsa error = iicbus_request_bus(device_get_parent(dev), dev, 250215142Sthompsa IIC_DONTWAIT); 251215142Sthompsa if (error) 252215142Sthompsa return (error); 253215142Sthompsa 254215142Sthompsa i2c_sendstart(sc); 255215142Sthompsa i2c_sendbyte(sc, PLD_ADDR & ~LSB); 256215142Sthompsa i2c_sendbyte(sc, sc->sc_latch); 257215142Sthompsa i2c_sendstop(sc); 258215142Sthompsa 259215142Sthompsa iicbus_release_bus(device_get_parent(dev), dev); 260215142Sthompsa 261215142Sthompsa return (0); 262215142Sthompsa} 263215142Sthompsa 264215142Sthompsastatic int 265215142Sthompsacambria_gpio_pin_max(device_t dev, int *maxpin) 266215142Sthompsa{ 267215142Sthompsa 268215142Sthompsa *maxpin = GPIO_PINS - 1; 269215142Sthompsa return (0); 270215142Sthompsa} 271215142Sthompsa 272215142Sthompsastatic int 273215142Sthompsacambria_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 274215142Sthompsa{ 275215142Sthompsa struct cambria_gpio_softc *sc = device_get_softc(dev); 276215142Sthompsa 277215142Sthompsa if (pin >= GPIO_PINS) 278215142Sthompsa return (EINVAL); 279215142Sthompsa 280215142Sthompsa *caps = sc->sc_pins[pin].gp_caps; 281215142Sthompsa return (0); 282215142Sthompsa} 283215142Sthompsa 284215142Sthompsastatic int 285215142Sthompsacambria_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 286215142Sthompsa{ 287215142Sthompsa struct cambria_gpio_softc *sc = device_get_softc(dev); 288215142Sthompsa 289215142Sthompsa if (pin >= GPIO_PINS) 290215142Sthompsa return (EINVAL); 291215142Sthompsa 292215142Sthompsa *flags = sc->sc_pins[pin].gp_flags; 293215142Sthompsa return (0); 294215142Sthompsa} 295215142Sthompsa 296215142Sthompsastatic int 297215142Sthompsacambria_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 298215142Sthompsa{ 299215142Sthompsa struct cambria_gpio_softc *sc = device_get_softc(dev); 300215142Sthompsa 301215142Sthompsa if (pin >= GPIO_PINS) 302215142Sthompsa return (EINVAL); 303215142Sthompsa 304215142Sthompsa memcpy(name, sc->sc_pins[pin].gp_name, GPIOMAXNAME); 305215142Sthompsa return (0); 306215142Sthompsa} 307215142Sthompsa 308215142Sthompsastatic int 309215142Sthompsacambria_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 310215142Sthompsa{ 311215142Sthompsa struct cambria_gpio_softc *sc = device_get_softc(dev); 312215142Sthompsa int error; 313226324Sthompsa uint8_t mask; 314215142Sthompsa 315226324Sthompsa mask = 1 << pin; 316226324Sthompsa 317215142Sthompsa if (pin >= GPIO_PINS) 318215142Sthompsa return (EINVAL); 319215142Sthompsa 320249449Sdim /* Check for unwanted flags. */ 321249449Sdim if ((flags & sc->sc_pins[pin].gp_caps) != flags) 322215142Sthompsa return (EINVAL); 323215142Sthompsa 324215142Sthompsa /* Can't mix input/output together */ 325215142Sthompsa if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 326215142Sthompsa (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) 327215142Sthompsa return (EINVAL); 328215142Sthompsa 329215142Sthompsa GPIO_LOCK(sc); 330215142Sthompsa sc->sc_pins[pin].gp_flags = flags; 331215142Sthompsa 332226324Sthompsa /* 333226324Sthompsa * Writing a logical one sets the signal high and writing a logical 334226324Sthompsa * zero sets the signal low. To configure a digital I/O signal as an 335226324Sthompsa * input, a logical one must first be written to the data bit to 336226324Sthompsa * three-state the associated output. 337226324Sthompsa */ 338226324Sthompsa if (flags & GPIO_PIN_INPUT || sc->sc_val & mask) 339226324Sthompsa sc->sc_latch |= mask; /* input or output & high */ 340226324Sthompsa else 341226324Sthompsa sc->sc_latch &= ~mask; 342215142Sthompsa error = cambria_gpio_write(sc); 343215142Sthompsa GPIO_UNLOCK(sc); 344215142Sthompsa 345215142Sthompsa return (error); 346215142Sthompsa} 347215142Sthompsa 348215142Sthompsastatic int 349215142Sthompsacambria_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 350215142Sthompsa{ 351215142Sthompsa struct cambria_gpio_softc *sc = device_get_softc(dev); 352215142Sthompsa int error; 353226324Sthompsa uint8_t mask; 354215142Sthompsa 355226324Sthompsa mask = 1 << pin; 356226324Sthompsa 357226324Sthompsa if (pin >= GPIO_PINS) 358215142Sthompsa return (EINVAL); 359215142Sthompsa GPIO_LOCK(sc); 360215142Sthompsa if (value) 361226324Sthompsa sc->sc_val |= mask; 362215142Sthompsa else 363226324Sthompsa sc->sc_val &= ~mask; 364226324Sthompsa 365226324Sthompsa if (sc->sc_pins[pin].gp_flags != GPIO_PIN_OUTPUT) { 366226324Sthompsa /* just save, altering the latch will disable input */ 367226324Sthompsa GPIO_UNLOCK(sc); 368226324Sthompsa return (0); 369226324Sthompsa } 370226324Sthompsa 371226324Sthompsa if (value) 372226324Sthompsa sc->sc_latch |= mask; 373226324Sthompsa else 374226324Sthompsa sc->sc_latch &= ~mask; 375215142Sthompsa error = cambria_gpio_write(sc); 376215142Sthompsa GPIO_UNLOCK(sc); 377215142Sthompsa 378215142Sthompsa return (error); 379215142Sthompsa} 380215142Sthompsa 381215142Sthompsastatic int 382215142Sthompsacambria_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 383215142Sthompsa{ 384215142Sthompsa struct cambria_gpio_softc *sc = device_get_softc(dev); 385215142Sthompsa int error = 0; 386215142Sthompsa 387215142Sthompsa if (pin >= GPIO_PINS) 388215142Sthompsa return (EINVAL); 389215142Sthompsa 390215142Sthompsa GPIO_LOCK(sc); 391215142Sthompsa if (sc->sc_pins[pin].gp_flags == GPIO_PIN_OUTPUT) 392215142Sthompsa *val = (sc->sc_latch & (1 << pin)) ? 1 : 0; 393215142Sthompsa else 394215142Sthompsa error = cambria_gpio_read(sc, pin, val); 395215142Sthompsa GPIO_UNLOCK(sc); 396215142Sthompsa 397215142Sthompsa return (error); 398215142Sthompsa} 399215142Sthompsa 400215142Sthompsastatic int 401215142Sthompsacambria_gpio_pin_toggle(device_t dev, uint32_t pin) 402215142Sthompsa{ 403215142Sthompsa struct cambria_gpio_softc *sc = device_get_softc(dev); 404226324Sthompsa int error = 0; 405215142Sthompsa 406226324Sthompsa if (pin >= GPIO_PINS) 407215142Sthompsa return (EINVAL); 408215142Sthompsa 409215142Sthompsa GPIO_LOCK(sc); 410226324Sthompsa sc->sc_val ^= (1 << pin); 411226324Sthompsa if (sc->sc_pins[pin].gp_flags == GPIO_PIN_OUTPUT) { 412226324Sthompsa sc->sc_latch ^= (1 << pin); 413226324Sthompsa error = cambria_gpio_write(sc); 414226324Sthompsa } 415215142Sthompsa GPIO_UNLOCK(sc); 416215142Sthompsa 417215142Sthompsa return (error); 418215142Sthompsa} 419215142Sthompsa 420215142Sthompsastatic int 421215142Sthompsacambria_gpio_probe(device_t dev) 422215142Sthompsa{ 423215142Sthompsa 424215142Sthompsa device_set_desc(dev, "Gateworks Cambria GPIO driver"); 425215142Sthompsa return (0); 426215142Sthompsa} 427215142Sthompsa 428215142Sthompsastatic int 429215142Sthompsacambria_gpio_attach(device_t dev) 430215142Sthompsa{ 431215142Sthompsa struct cambria_gpio_softc *sc = device_get_softc(dev); 432215142Sthompsa int pin; 433215142Sthompsa 434215142Sthompsa sc->sc_dev = dev; 435215142Sthompsa sc->sc_iot = ixp425_softc->sc_iot; 436215142Sthompsa sc->sc_gpio_ioh = ixp425_softc->sc_gpio_ioh; 437215142Sthompsa 438239351Srpaulo mtx_init(&sc->sc_mtx, device_get_nameunit(dev), NULL, MTX_DEF); 439215142Sthompsa 440215142Sthompsa for (pin = 0; pin < GPIO_PINS; pin++) { 441215142Sthompsa struct cambria_gpio_pin *p = &cambria_gpio_pins[pin]; 442215142Sthompsa 443215142Sthompsa strncpy(sc->sc_pins[pin].gp_name, p->name, GPIOMAXNAME); 444215142Sthompsa sc->sc_pins[pin].gp_pin = pin; 445215142Sthompsa sc->sc_pins[pin].gp_caps = GPIO_PIN_INPUT|GPIO_PIN_OUTPUT; 446215142Sthompsa sc->sc_pins[pin].gp_flags = 0; 447215142Sthompsa cambria_gpio_pin_setflags(dev, pin, p->flags); 448215142Sthompsa } 449215142Sthompsa 450215142Sthompsa device_add_child(dev, "gpioc", device_get_unit(dev)); 451215142Sthompsa device_add_child(dev, "gpiobus", device_get_unit(dev)); 452215142Sthompsa return (bus_generic_attach(dev)); 453215142Sthompsa} 454215142Sthompsa 455215142Sthompsastatic int 456215142Sthompsacambria_gpio_detach(device_t dev) 457215142Sthompsa{ 458215142Sthompsa struct cambria_gpio_softc *sc = device_get_softc(dev); 459215142Sthompsa 460215142Sthompsa KASSERT(mtx_initialized(&sc->sc_mtx), ("gpio mutex not initialized")); 461215142Sthompsa 462215142Sthompsa bus_generic_detach(dev); 463215142Sthompsa 464215142Sthompsa mtx_destroy(&sc->sc_mtx); 465215142Sthompsa 466215142Sthompsa return(0); 467215142Sthompsa} 468215142Sthompsa 469215142Sthompsastatic device_method_t cambria_gpio_methods[] = { 470215142Sthompsa DEVMETHOD(device_probe, cambria_gpio_probe), 471215142Sthompsa DEVMETHOD(device_attach, cambria_gpio_attach), 472215142Sthompsa DEVMETHOD(device_detach, cambria_gpio_detach), 473215142Sthompsa 474215142Sthompsa /* GPIO protocol */ 475215142Sthompsa DEVMETHOD(gpio_pin_max, cambria_gpio_pin_max), 476215142Sthompsa DEVMETHOD(gpio_pin_getname, cambria_gpio_pin_getname), 477215142Sthompsa DEVMETHOD(gpio_pin_getflags, cambria_gpio_pin_getflags), 478215142Sthompsa DEVMETHOD(gpio_pin_getcaps, cambria_gpio_pin_getcaps), 479215142Sthompsa DEVMETHOD(gpio_pin_setflags, cambria_gpio_pin_setflags), 480215142Sthompsa DEVMETHOD(gpio_pin_get, cambria_gpio_pin_get), 481215142Sthompsa DEVMETHOD(gpio_pin_set, cambria_gpio_pin_set), 482215142Sthompsa DEVMETHOD(gpio_pin_toggle, cambria_gpio_pin_toggle), 483215142Sthompsa {0, 0}, 484215142Sthompsa}; 485215142Sthompsa 486215142Sthompsastatic driver_t cambria_gpio_driver = { 487215142Sthompsa "gpio_cambria", 488215142Sthompsa cambria_gpio_methods, 489215142Sthompsa sizeof(struct cambria_gpio_softc), 490215142Sthompsa}; 491215142Sthompsastatic devclass_t cambria_gpio_devclass; 492215142Sthompsaextern devclass_t gpiobus_devclass, gpioc_devclass; 493215142Sthompsaextern driver_t gpiobus_driver, gpioc_driver; 494215142Sthompsa 495215142SthompsaDRIVER_MODULE(gpio_cambria, iicbus, cambria_gpio_driver, cambria_gpio_devclass, 0, 0); 496215142SthompsaDRIVER_MODULE(gpiobus, gpio_cambria, gpiobus_driver, gpiobus_devclass, 0, 0); 497215142SthompsaDRIVER_MODULE(gpioc, gpio_cambria, gpioc_driver, gpioc_devclass, 0, 0); 498215142SthompsaMODULE_VERSION(gpio_cambria, 1); 499215142SthompsaMODULE_DEPEND(gpio_cambria, iicbus, 1, 1, 1); 500