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