gpioled.c revision 213277
1213237Sgonzo/*-
2213237Sgonzo * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
3213237Sgonzo * All rights reserved.
4213237Sgonzo *
5213237Sgonzo * Redistribution and use in source and binary forms, with or without
6213237Sgonzo * modification, are permitted provided that the following conditions
7213237Sgonzo * are met:
8213237Sgonzo * 1. Redistributions of source code must retain the above copyright
9213237Sgonzo *    notice, this list of conditions and the following disclaimer.
10213237Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
11213237Sgonzo *    notice, this list of conditions and the following disclaimer in the
12213237Sgonzo *    documentation and/or other materials provided with the distribution.
13213237Sgonzo *
14213277Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15213277Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16213277Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17213277Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18213277Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19213277Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20213277Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21213277Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22213277Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23213277Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24213277Sgonzo * SUCH DAMAGE.
25213237Sgonzo */
26213237Sgonzo
27213237Sgonzo#include <sys/cdefs.h>
28213237Sgonzo__FBSDID("$FreeBSD: head/sys/dev/gpio/gpioled.c 213277 2010-09-29 20:53:33Z gonzo $");
29213237Sgonzo
30213237Sgonzo#include <sys/param.h>
31213237Sgonzo#include <sys/systm.h>
32213237Sgonzo#include <sys/bio.h>
33213237Sgonzo#include <sys/bus.h>
34213237Sgonzo#include <sys/conf.h>
35213237Sgonzo#include <sys/kernel.h>
36213237Sgonzo#include <sys/kthread.h>
37213237Sgonzo#include <sys/lock.h>
38213237Sgonzo#include <sys/malloc.h>
39213237Sgonzo#include <sys/module.h>
40213237Sgonzo#include <sys/mutex.h>
41213237Sgonzo
42213237Sgonzo#include <dev/led/led.h>
43213237Sgonzo#include <sys/gpio.h>
44213237Sgonzo#include "gpiobus_if.h"
45213237Sgonzo
46213237Sgonzo/*
47213237Sgonzo * Only one pin for led
48213237Sgonzo */
49213237Sgonzo#define	GPIOLED_PIN	0
50213237Sgonzo
51213237Sgonzo#define GPIOLED_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
52213237Sgonzo#define	GPIOLED_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
53213237Sgonzo#define GPIOLED_LOCK_INIT(_sc) \
54213237Sgonzo	mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \
55213237Sgonzo	    "gpioled", MTX_DEF)
56213237Sgonzo#define GPIOLED_LOCK_DESTROY(_sc)	mtx_destroy(&_sc->sc_mtx);
57213237Sgonzo
58213237Sgonzostruct gpioled_softc
59213237Sgonzo{
60213237Sgonzo	device_t	sc_dev;
61213237Sgonzo	device_t	sc_busdev;
62213237Sgonzo	struct mtx	sc_mtx;
63213237Sgonzo	struct cdev	*sc_leddev;
64213237Sgonzo};
65213237Sgonzo
66213237Sgonzostatic void gpioled_control(void *, int);
67213237Sgonzostatic int gpioled_probe(device_t);
68213237Sgonzostatic int gpioled_attach(device_t);
69213237Sgonzostatic int gpioled_detach(device_t);
70213237Sgonzo
71213237Sgonzostatic void
72213237Sgonzogpioled_control(void *priv, int onoff)
73213237Sgonzo{
74213237Sgonzo	struct gpioled_softc *sc = priv;
75213237Sgonzo	GPIOLED_LOCK(sc);
76213237Sgonzo	GPIOBUS_LOCK_BUS(sc->sc_busdev);
77213237Sgonzo	GPIOBUS_ACQUIRE_BUS(sc->sc_busdev, sc->sc_dev);
78213237Sgonzo	GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN,
79213237Sgonzo	    onoff ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
80213237Sgonzo	GPIOBUS_RELEASE_BUS(sc->sc_busdev, sc->sc_dev);
81213237Sgonzo	GPIOBUS_UNLOCK_BUS(sc->sc_busdev);
82213237Sgonzo	GPIOLED_UNLOCK(sc);
83213237Sgonzo}
84213237Sgonzo
85213237Sgonzostatic int
86213237Sgonzogpioled_probe(device_t dev)
87213237Sgonzo{
88213237Sgonzo	device_set_desc(dev, "GPIO led");
89213237Sgonzo	return (0);
90213237Sgonzo}
91213237Sgonzo
92213237Sgonzostatic int
93213237Sgonzogpioled_attach(device_t dev)
94213237Sgonzo{
95213237Sgonzo	struct gpioled_softc *sc;
96213237Sgonzo	const char *name;
97213237Sgonzo
98213237Sgonzo	sc = device_get_softc(dev);
99213237Sgonzo	sc->sc_dev = dev;
100213237Sgonzo	sc->sc_busdev = device_get_parent(dev);
101213237Sgonzo	GPIOLED_LOCK_INIT(sc);
102213237Sgonzo	if (resource_string_value(device_get_name(dev),
103213237Sgonzo	    device_get_unit(dev), "name", &name))
104213237Sgonzo		name = NULL;
105213237Sgonzo
106213237Sgonzo	sc->sc_leddev = led_create(gpioled_control, sc, name ? name :
107213237Sgonzo	    device_get_nameunit(dev));
108213237Sgonzo
109213237Sgonzo	return (0);
110213237Sgonzo}
111213237Sgonzo
112213237Sgonzostatic int
113213237Sgonzogpioled_detach(device_t dev)
114213237Sgonzo{
115213237Sgonzo	struct gpioled_softc *sc;
116213237Sgonzo
117213237Sgonzo	sc = device_get_softc(dev);
118213237Sgonzo	if (sc->sc_leddev) {
119213237Sgonzo		led_destroy(sc->sc_leddev);
120213237Sgonzo		sc->sc_leddev = NULL;
121213237Sgonzo	}
122213237Sgonzo	GPIOLED_LOCK_DESTROY(sc);
123213237Sgonzo	return (0);
124213237Sgonzo}
125213237Sgonzo
126213237Sgonzostatic devclass_t gpioled_devclass;
127213237Sgonzo
128213237Sgonzostatic device_method_t gpioled_methods[] = {
129213237Sgonzo	/* Device interface */
130213237Sgonzo	DEVMETHOD(device_probe,		gpioled_probe),
131213237Sgonzo	DEVMETHOD(device_attach,	gpioled_attach),
132213237Sgonzo	DEVMETHOD(device_detach,	gpioled_detach),
133213237Sgonzo
134213237Sgonzo	{ 0, 0 }
135213237Sgonzo};
136213237Sgonzo
137213237Sgonzostatic driver_t gpioled_driver = {
138213237Sgonzo	"gpioled",
139213237Sgonzo	gpioled_methods,
140213237Sgonzo	sizeof(struct gpioled_softc),
141213237Sgonzo};
142213237Sgonzo
143213237SgonzoDRIVER_MODULE(gpioled, gpiobus, gpioled_driver, gpioled_devclass, 0, 0);
144