xref: /freebsd-src/sys/dev/gpio/gpioled.c (revision 685dc743dc3b5645e34836464128e1c0558b404b)
16b34b16eSOleksandr Tymoshenko /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
3718cf2ccSPedro F. Giffuni  *
46b34b16eSOleksandr Tymoshenko  * Copyright (c) 2009 Oleksandr Tymoshenko <gonzo@freebsd.org>
56b34b16eSOleksandr Tymoshenko  * All rights reserved.
66b34b16eSOleksandr Tymoshenko  *
76b34b16eSOleksandr Tymoshenko  * Redistribution and use in source and binary forms, with or without
86b34b16eSOleksandr Tymoshenko  * modification, are permitted provided that the following conditions
96b34b16eSOleksandr Tymoshenko  * are met:
106b34b16eSOleksandr Tymoshenko  * 1. Redistributions of source code must retain the above copyright
116b34b16eSOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer.
126b34b16eSOleksandr Tymoshenko  * 2. Redistributions in binary form must reproduce the above copyright
136b34b16eSOleksandr Tymoshenko  *    notice, this list of conditions and the following disclaimer in the
146b34b16eSOleksandr Tymoshenko  *    documentation and/or other materials provided with the distribution.
156b34b16eSOleksandr Tymoshenko  *
165f958b85SOleksandr Tymoshenko  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
175f958b85SOleksandr Tymoshenko  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
185f958b85SOleksandr Tymoshenko  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
195f958b85SOleksandr Tymoshenko  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
205f958b85SOleksandr Tymoshenko  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
215f958b85SOleksandr Tymoshenko  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
225f958b85SOleksandr Tymoshenko  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
235f958b85SOleksandr Tymoshenko  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
245f958b85SOleksandr Tymoshenko  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
255f958b85SOleksandr Tymoshenko  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
265f958b85SOleksandr Tymoshenko  * SUCH DAMAGE.
276b34b16eSOleksandr Tymoshenko  */
286b34b16eSOleksandr Tymoshenko 
296b34b16eSOleksandr Tymoshenko #include <sys/cdefs.h>
309a2a079aSLuiz Otavio O Souza #include "opt_platform.h"
319a2a079aSLuiz Otavio O Souza 
326b34b16eSOleksandr Tymoshenko #include <sys/param.h>
336b34b16eSOleksandr Tymoshenko #include <sys/systm.h>
346b34b16eSOleksandr Tymoshenko #include <sys/bus.h>
35409c1839SLuiz Otavio O Souza #include <sys/gpio.h>
366b34b16eSOleksandr Tymoshenko #include <sys/kernel.h>
376b34b16eSOleksandr Tymoshenko #include <sys/lock.h>
386b34b16eSOleksandr Tymoshenko #include <sys/malloc.h>
396b34b16eSOleksandr Tymoshenko #include <sys/module.h>
406b34b16eSOleksandr Tymoshenko #include <sys/mutex.h>
416b34b16eSOleksandr Tymoshenko 
42409c1839SLuiz Otavio O Souza #include <dev/gpio/gpiobusvar.h>
436b34b16eSOleksandr Tymoshenko #include <dev/led/led.h>
44409c1839SLuiz Otavio O Souza 
456b34b16eSOleksandr Tymoshenko #include "gpiobus_if.h"
466b34b16eSOleksandr Tymoshenko 
476b34b16eSOleksandr Tymoshenko /*
486b34b16eSOleksandr Tymoshenko  * Only one pin for led
496b34b16eSOleksandr Tymoshenko  */
506b34b16eSOleksandr Tymoshenko #define	GPIOLED_PIN	0
516b34b16eSOleksandr Tymoshenko 
526b34b16eSOleksandr Tymoshenko #define	GPIOLED_LOCK(_sc)		mtx_lock(&(_sc)->sc_mtx)
536b34b16eSOleksandr Tymoshenko #define	GPIOLED_UNLOCK(_sc)		mtx_unlock(&(_sc)->sc_mtx)
54fc5f218aSLuiz Otavio O Souza #define	GPIOLED_LOCK_INIT(_sc)		mtx_init(&(_sc)->sc_mtx,	\
55fc5f218aSLuiz Otavio O Souza     device_get_nameunit((_sc)->sc_dev), "gpioled", MTX_DEF)
56fc5f218aSLuiz Otavio O Souza #define	GPIOLED_LOCK_DESTROY(_sc)	mtx_destroy(&(_sc)->sc_mtx)
576b34b16eSOleksandr Tymoshenko 
586b34b16eSOleksandr Tymoshenko struct gpioled_softc
596b34b16eSOleksandr Tymoshenko {
606b34b16eSOleksandr Tymoshenko 	device_t	sc_dev;
616b34b16eSOleksandr Tymoshenko 	device_t	sc_busdev;
626b34b16eSOleksandr Tymoshenko 	struct mtx	sc_mtx;
636b34b16eSOleksandr Tymoshenko 	struct cdev	*sc_leddev;
64d75e8c50SAdrian Chadd 	int		sc_invert;
656b34b16eSOleksandr Tymoshenko };
666b34b16eSOleksandr Tymoshenko 
676b34b16eSOleksandr Tymoshenko static void gpioled_control(void *, int);
686b34b16eSOleksandr Tymoshenko static int gpioled_probe(device_t);
696b34b16eSOleksandr Tymoshenko static int gpioled_attach(device_t);
706b34b16eSOleksandr Tymoshenko static int gpioled_detach(device_t);
716b34b16eSOleksandr Tymoshenko 
726b34b16eSOleksandr Tymoshenko static void
gpioled_control(void * priv,int onoff)736b34b16eSOleksandr Tymoshenko gpioled_control(void *priv, int onoff)
746b34b16eSOleksandr Tymoshenko {
759d35acacSLuiz Otavio O Souza 	struct gpioled_softc *sc;
769d35acacSLuiz Otavio O Souza 
779d35acacSLuiz Otavio O Souza 	sc = (struct gpioled_softc *)priv;
786b34b16eSOleksandr Tymoshenko 	GPIOLED_LOCK(sc);
7903302aa3SLuiz Otavio O Souza 	if (GPIOBUS_PIN_SETFLAGS(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN,
8003302aa3SLuiz Otavio O Souza 	    GPIO_PIN_OUTPUT) == 0) {
81d75e8c50SAdrian Chadd 		if (sc->sc_invert)
82d75e8c50SAdrian Chadd 			onoff = !onoff;
836b34b16eSOleksandr Tymoshenko 		GPIOBUS_PIN_SET(sc->sc_busdev, sc->sc_dev, GPIOLED_PIN,
846b34b16eSOleksandr Tymoshenko 		    onoff ? GPIO_PIN_HIGH : GPIO_PIN_LOW);
8503302aa3SLuiz Otavio O Souza 	}
866b34b16eSOleksandr Tymoshenko 	GPIOLED_UNLOCK(sc);
876b34b16eSOleksandr Tymoshenko }
886b34b16eSOleksandr Tymoshenko 
896b34b16eSOleksandr Tymoshenko static int
gpioled_probe(device_t dev)906b34b16eSOleksandr Tymoshenko gpioled_probe(device_t dev)
916b34b16eSOleksandr Tymoshenko {
926b34b16eSOleksandr Tymoshenko 	device_set_desc(dev, "GPIO led");
939a2a079aSLuiz Otavio O Souza 
94fc5f218aSLuiz Otavio O Souza 	return (BUS_PROBE_DEFAULT);
956b34b16eSOleksandr Tymoshenko }
966b34b16eSOleksandr Tymoshenko 
976b34b16eSOleksandr Tymoshenko static int
gpioled_attach(device_t dev)986b34b16eSOleksandr Tymoshenko gpioled_attach(device_t dev)
996b34b16eSOleksandr Tymoshenko {
1006b34b16eSOleksandr Tymoshenko 	struct gpioled_softc *sc;
1013a9ac403SGanbold Tsagaankhuu 	int state;
1026b34b16eSOleksandr Tymoshenko 	const char *name;
1036b34b16eSOleksandr Tymoshenko 
1046b34b16eSOleksandr Tymoshenko 	sc = device_get_softc(dev);
1056b34b16eSOleksandr Tymoshenko 	sc->sc_dev = dev;
1066b34b16eSOleksandr Tymoshenko 	sc->sc_busdev = device_get_parent(dev);
1076b34b16eSOleksandr Tymoshenko 	GPIOLED_LOCK_INIT(sc);
1083a9ac403SGanbold Tsagaankhuu 
1093a9ac403SGanbold Tsagaankhuu 	state = 0;
1103a9ac403SGanbold Tsagaankhuu 
1116b34b16eSOleksandr Tymoshenko 	if (resource_string_value(device_get_name(dev),
1126b34b16eSOleksandr Tymoshenko 	    device_get_unit(dev), "name", &name))
1136b34b16eSOleksandr Tymoshenko 		name = NULL;
114d75e8c50SAdrian Chadd 	resource_int_value(device_get_name(dev),
115d75e8c50SAdrian Chadd 	    device_get_unit(dev), "invert", &sc->sc_invert);
116211bd53aSAndriy Gapon 	resource_int_value(device_get_name(dev),
117211bd53aSAndriy Gapon 	    device_get_unit(dev), "state", &state);
1186b34b16eSOleksandr Tymoshenko 
1193a9ac403SGanbold Tsagaankhuu 	sc->sc_leddev = led_create_state(gpioled_control, sc, name ? name :
1203a9ac403SGanbold Tsagaankhuu 	    device_get_nameunit(dev), state);
1216b34b16eSOleksandr Tymoshenko 
1226b34b16eSOleksandr Tymoshenko 	return (0);
1236b34b16eSOleksandr Tymoshenko }
1246b34b16eSOleksandr Tymoshenko 
1256b34b16eSOleksandr Tymoshenko static int
gpioled_detach(device_t dev)1266b34b16eSOleksandr Tymoshenko gpioled_detach(device_t dev)
1276b34b16eSOleksandr Tymoshenko {
1286b34b16eSOleksandr Tymoshenko 	struct gpioled_softc *sc;
1296b34b16eSOleksandr Tymoshenko 
1306b34b16eSOleksandr Tymoshenko 	sc = device_get_softc(dev);
1316b34b16eSOleksandr Tymoshenko 	if (sc->sc_leddev) {
1326b34b16eSOleksandr Tymoshenko 		led_destroy(sc->sc_leddev);
1336b34b16eSOleksandr Tymoshenko 		sc->sc_leddev = NULL;
1346b34b16eSOleksandr Tymoshenko 	}
1356b34b16eSOleksandr Tymoshenko 	GPIOLED_LOCK_DESTROY(sc);
1366b34b16eSOleksandr Tymoshenko 	return (0);
1376b34b16eSOleksandr Tymoshenko }
1386b34b16eSOleksandr Tymoshenko 
1396b34b16eSOleksandr Tymoshenko static device_method_t gpioled_methods[] = {
1406b34b16eSOleksandr Tymoshenko 	/* Device interface */
1416b34b16eSOleksandr Tymoshenko 	DEVMETHOD(device_probe,		gpioled_probe),
1426b34b16eSOleksandr Tymoshenko 	DEVMETHOD(device_attach,	gpioled_attach),
1436b34b16eSOleksandr Tymoshenko 	DEVMETHOD(device_detach,	gpioled_detach),
1446b34b16eSOleksandr Tymoshenko 
145e2a1919dSOleksandr Tymoshenko 	DEVMETHOD_END
1466b34b16eSOleksandr Tymoshenko };
1476b34b16eSOleksandr Tymoshenko 
1486b34b16eSOleksandr Tymoshenko static driver_t gpioled_driver = {
1496b34b16eSOleksandr Tymoshenko 	"gpioled",
1506b34b16eSOleksandr Tymoshenko 	gpioled_methods,
1516b34b16eSOleksandr Tymoshenko 	sizeof(struct gpioled_softc),
1526b34b16eSOleksandr Tymoshenko };
1536b34b16eSOleksandr Tymoshenko 
15484c5f982SJohn Baldwin DRIVER_MODULE(gpioled, gpiobus, gpioled_driver, 0, 0);
155e9aebbb0SLuiz Otavio O Souza MODULE_DEPEND(gpioled, gpiobus, 1, 1, 1);
156211bd53aSAndriy Gapon MODULE_VERSION(gpioled, 1);
157