gpioc.c revision 233767
1121054Semax/*- 2121054Semax * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org> 3121054Semax * All rights reserved. 4121054Semax * 5121054Semax * Redistribution and use in source and binary forms, with or without 6121054Semax * modification, are permitted provided that the following conditions 7121054Semax * are met: 8121054Semax * 1. Redistributions of source code must retain the above copyright 9121054Semax * notice, this list of conditions and the following disclaimer. 10121054Semax * 2. Redistributions in binary form must reproduce the above copyright 11121054Semax * notice, this list of conditions and the following disclaimer in the 12121054Semax * documentation and/or other materials provided with the distribution. 13121054Semax * 14121054Semax * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15121054Semax * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16121054Semax * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17121054Semax * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18121054Semax * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19121054Semax * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20121054Semax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21121054Semax * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22121054Semax * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23121054Semax * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24121054Semax * SUCH DAMAGE. 25121054Semax */ 26121054Semax 27121054Semax#include <sys/cdefs.h> 28121054Semax__FBSDID("$FreeBSD: head/sys/dev/gpio/gpioc.c 233767 2012-04-02 00:11:26Z gonzo $"); 29121054Semax 30121054Semax#include <sys/param.h> 31121054Semax#include <sys/systm.h> 32121054Semax#include <sys/types.h> 33121054Semax 34121054Semax#include <sys/bus.h> 35121054Semax#include <sys/conf.h> 36121054Semax#include <sys/ioccom.h> 37121054Semax#include <sys/kernel.h> 38121054Semax#include <sys/malloc.h> 39121054Semax#include <sys/module.h> 40121054Semax#include <sys/queue.h> 41121054Semax#include <machine/bus.h> 42121054Semax#include <machine/resource.h> 43121054Semax 44121054Semax#include <sys/gpio.h> 45121054Semax#include "gpio_if.h" 46121054Semax 47124305Semax#undef GPIOC_DEBUG 48124305Semax#ifdef GPIOC_DEBUG 49124305Semax#define dprintf printf 50121054Semax#else 51121054Semax#define dprintf(x, arg...) 52124305Semax#endif 53124305Semax 54121054Semaxstatic int gpioc_probe(device_t dev); 55121054Semaxstatic int gpioc_attach(device_t dev); 56121054Semaxstatic int gpioc_detach(device_t dev); 57124305Semax 58138633Semaxstatic d_ioctl_t gpioc_ioctl; 59138633Semax 60121054Semaxstatic struct cdevsw gpioc_cdevsw = { 61121054Semax .d_version = D_VERSION, 62121054Semax .d_ioctl = gpioc_ioctl, 63121054Semax .d_name = "gpioc", 64121054Semax}; 65121054Semax 66121054Semaxstruct gpioc_softc { 67121054Semax device_t sc_dev; /* gpiocX dev */ 68121054Semax device_t sc_pdev; /* gpioX dev */ 69121054Semax struct cdev *sc_ctl_dev; /* controller device */ 70121054Semax int sc_unit; 71138633Semax}; 72138633Semax 73121054Semaxstatic int 74121054Semaxgpioc_probe(device_t dev) 75138633Semax{ 76138633Semax device_set_desc(dev, "GPIO controller"); 77138633Semax return (0); 78138633Semax} 79138633Semax 80138633Semaxstatic int 81138633Semaxgpioc_attach(device_t dev) 82138633Semax{ 83138633Semax struct gpioc_softc *sc = device_get_softc(dev); 84138633Semax 85138633Semax sc->sc_dev = dev; 86138633Semax sc->sc_pdev = device_get_parent(dev); 87138633Semax sc->sc_unit = device_get_unit(dev); 88138633Semax sc->sc_ctl_dev = make_dev(&gpioc_cdevsw, sc->sc_unit, 89138633Semax UID_ROOT, GID_WHEEL, 0600, "gpioc%d", sc->sc_unit); 90138633Semax if (!sc->sc_ctl_dev) { 91138633Semax printf("Failed to create gpioc%d", sc->sc_unit); 92138633Semax return (ENXIO); 93124305Semax } 94121054Semax sc->sc_ctl_dev->si_drv1 = sc; 95124305Semax 96121054Semax return (0); 97124305Semax} 98121054Semax 99121054Semaxstatic int 100121054Semaxgpioc_detach(device_t dev) 101121054Semax{ 102121054Semax struct gpioc_softc *sc = device_get_softc(dev); 103121054Semax int err; 104121054Semax 105121054Semax if (sc->sc_ctl_dev) 106121054Semax destroy_dev(sc->sc_ctl_dev); 107121054Semax 108121054Semax if ((err = bus_generic_detach(dev)) != 0) 109121054Semax return (err); 110121054Semax 111121054Semax return (0); 112121054Semax} 113121054Semax 114121054Semaxstatic int 115121054Semaxgpioc_ioctl(struct cdev *cdev, u_long cmd, caddr_t arg, int fflag, 116121054Semax struct thread *td) 117121054Semax{ 118121054Semax int max_pin, res; 119138633Semax struct gpioc_softc *sc = cdev->si_drv1; 120138633Semax struct gpio_pin pin; 121138633Semax struct gpio_req req; 122138633Semax 123138633Semax switch (cmd) { 124138633Semax case GPIOMAXPIN: 125138633Semax max_pin = -1; 126138633Semax res = GPIO_PIN_MAX(sc->sc_pdev, &max_pin); 127138633Semax bcopy(&max_pin, arg, sizeof(max_pin)); 128138633Semax break; 129138633Semax case GPIOGETCONFIG: 130138633Semax bcopy(arg, &pin, sizeof(pin)); 131138633Semax dprintf("get config pin %d\n", pin.gp_pin); 132138633Semax res = GPIO_PIN_GETFLAGS(sc->sc_pdev, pin.gp_pin, 133138633Semax &pin.gp_flags); 134121054Semax /* Fail early */ 135121054Semax if (res) 136121054Semax break; 137121054Semax GPIO_PIN_GETCAPS(sc->sc_pdev, pin.gp_pin, &pin.gp_caps); 138121054Semax GPIO_PIN_GETNAME(sc->sc_pdev, pin.gp_pin, pin.gp_name); 139121054Semax bcopy(&pin, arg, sizeof(pin)); 140121054Semax break; 141121054Semax case GPIOSETCONFIG: 142124305Semax bcopy(arg, &pin, sizeof(pin)); 143121054Semax dprintf("set config pin %d\n", pin.gp_pin); 144121054Semax res = GPIO_PIN_SETFLAGS(sc->sc_pdev, pin.gp_pin, 145121054Semax pin.gp_flags); 146121054Semax break; 147121054Semax case GPIOGET: 148121054Semax bcopy(arg, &req, sizeof(req)); 149121054Semax res = GPIO_PIN_GET(sc->sc_pdev, req.gp_pin, 150121054Semax &req.gp_value); 151121054Semax dprintf("read pin %d -> %d\n", 152121054Semax req.gp_pin, req.gp_value); 153121054Semax bcopy(&req, arg, sizeof(req)); 154121054Semax break; 155121054Semax case GPIOSET: 156121054Semax bcopy(arg, &req, sizeof(req)); 157121054Semax res = GPIO_PIN_SET(sc->sc_pdev, req.gp_pin, 158121054Semax req.gp_value); 159121054Semax dprintf("write pin %d -> %d\n", 160121054Semax req.gp_pin, req.gp_value); 161121054Semax break; 162121054Semax case GPIOTOGGLE: 163121054Semax bcopy(arg, &req, sizeof(req)); 164121054Semax dprintf("toggle pin %d\n", 165121054Semax req.gp_pin); 166121054Semax res = GPIO_PIN_TOGGLE(sc->sc_pdev, req.gp_pin); 167124758Semax break; 168124758Semax default: 169124758Semax return (ENOTTY); 170124758Semax break; 171121054Semax } 172121054Semax 173121054Semax return (res); 174121054Semax} 175121054Semax 176121054Semaxstatic device_method_t gpioc_methods[] = { 177121054Semax /* Device interface */ 178121054Semax DEVMETHOD(device_probe, gpioc_probe), 179121054Semax DEVMETHOD(device_attach, gpioc_attach), 180121054Semax DEVMETHOD(device_detach, gpioc_detach), 181121054Semax DEVMETHOD(device_shutdown, bus_generic_shutdown), 182124758Semax DEVMETHOD(device_suspend, bus_generic_suspend), 183124758Semax DEVMETHOD(device_resume, bus_generic_resume), 184124758Semax 185124758Semax { 0, 0 } 186121054Semax}; 187121054Semax 188121054Semaxdriver_t gpioc_driver = { 189121054Semax "gpioc", 190121054Semax gpioc_methods, 191121054Semax sizeof(struct gpioc_softc) 192121054Semax}; 193121054Semax 194121054Semaxdevclass_t gpioc_devclass; 195121054Semax 196121054SemaxDRIVER_MODULE(gpioc, gpio, gpioc_driver, gpioc_devclass, 0, 0); 197121054SemaxMODULE_VERSION(gpioc, 1); 198121054Semax