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