12cfe870aSOleksandr Tymoshenko /*-
24d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
32cfe870aSOleksandr Tymoshenko *
42cfe870aSOleksandr Tymoshenko * Copyright (c) 2020 Oleksandr Tymoshenko <gonzo@FreeBSD.org>
52cfe870aSOleksandr Tymoshenko *
62cfe870aSOleksandr Tymoshenko * Redistribution and use in source and binary forms, with or without
72cfe870aSOleksandr Tymoshenko * modification, are permitted provided that the following conditions
82cfe870aSOleksandr Tymoshenko * are met:
92cfe870aSOleksandr Tymoshenko * 1. Redistributions of source code must retain the above copyright
102cfe870aSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer.
112cfe870aSOleksandr Tymoshenko * 2. Redistributions in binary form must reproduce the above copyright
122cfe870aSOleksandr Tymoshenko * notice, this list of conditions and the following disclaimer in the
132cfe870aSOleksandr Tymoshenko * documentation and/or other materials provided with the distribution.
142cfe870aSOleksandr Tymoshenko *
152cfe870aSOleksandr Tymoshenko * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
162cfe870aSOleksandr Tymoshenko * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
172cfe870aSOleksandr Tymoshenko * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
182cfe870aSOleksandr Tymoshenko * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
192cfe870aSOleksandr Tymoshenko * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
202cfe870aSOleksandr Tymoshenko * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
212cfe870aSOleksandr Tymoshenko * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
222cfe870aSOleksandr Tymoshenko * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
232cfe870aSOleksandr Tymoshenko * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
242cfe870aSOleksandr Tymoshenko * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
252cfe870aSOleksandr Tymoshenko * SUCH DAMAGE.
262cfe870aSOleksandr Tymoshenko */
272cfe870aSOleksandr Tymoshenko
282cfe870aSOleksandr Tymoshenko #include <sys/param.h>
292cfe870aSOleksandr Tymoshenko #include <sys/systm.h>
302cfe870aSOleksandr Tymoshenko #include <sys/bus.h>
312cfe870aSOleksandr Tymoshenko #include <sys/kernel.h>
322cfe870aSOleksandr Tymoshenko #include <sys/lock.h>
332cfe870aSOleksandr Tymoshenko #include <sys/module.h>
342cfe870aSOleksandr Tymoshenko #include <sys/mutex.h>
352cfe870aSOleksandr Tymoshenko #include <sys/rman.h>
362cfe870aSOleksandr Tymoshenko #include <sys/resource.h>
372cfe870aSOleksandr Tymoshenko #include <machine/bus.h>
382cfe870aSOleksandr Tymoshenko
392cfe870aSOleksandr Tymoshenko #include <dev/ofw/ofw_bus.h>
402cfe870aSOleksandr Tymoshenko #include <dev/ofw/ofw_bus_subr.h>
412cfe870aSOleksandr Tymoshenko
42*b2f0caf1SEmmanuel Vadot #include <dev/regulator/regulator.h>
432cfe870aSOleksandr Tymoshenko #include <dev/gpio/gpiobusvar.h>
442cfe870aSOleksandr Tymoshenko
452cfe870aSOleksandr Tymoshenko #include "opt_snd.h"
462cfe870aSOleksandr Tymoshenko #include <dev/sound/pcm/sound.h>
472cfe870aSOleksandr Tymoshenko #include <dev/sound/fdt/audio_dai.h>
482cfe870aSOleksandr Tymoshenko #include "audio_dai_if.h"
492cfe870aSOleksandr Tymoshenko
502cfe870aSOleksandr Tymoshenko static struct ofw_compat_data compat_data[] = {
512cfe870aSOleksandr Tymoshenko { "simple-audio-amplifier", 1},
522cfe870aSOleksandr Tymoshenko { NULL, 0}
532cfe870aSOleksandr Tymoshenko };
542cfe870aSOleksandr Tymoshenko
552cfe870aSOleksandr Tymoshenko struct simple_amp_softc {
562cfe870aSOleksandr Tymoshenko device_t dev;
572cfe870aSOleksandr Tymoshenko regulator_t supply_vcc;
582cfe870aSOleksandr Tymoshenko gpio_pin_t gpio_enable;
592cfe870aSOleksandr Tymoshenko bool gpio_is_valid;
602cfe870aSOleksandr Tymoshenko };
612cfe870aSOleksandr Tymoshenko
622cfe870aSOleksandr Tymoshenko static int simple_amp_probe(device_t dev);
632cfe870aSOleksandr Tymoshenko static int simple_amp_attach(device_t dev);
642cfe870aSOleksandr Tymoshenko static int simple_amp_detach(device_t dev);
652cfe870aSOleksandr Tymoshenko
662cfe870aSOleksandr Tymoshenko static int
simple_amp_probe(device_t dev)672cfe870aSOleksandr Tymoshenko simple_amp_probe(device_t dev)
682cfe870aSOleksandr Tymoshenko {
692cfe870aSOleksandr Tymoshenko if (!ofw_bus_status_okay(dev))
702cfe870aSOleksandr Tymoshenko return (ENXIO);
712cfe870aSOleksandr Tymoshenko
722cfe870aSOleksandr Tymoshenko if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
732cfe870aSOleksandr Tymoshenko return (ENXIO);
742cfe870aSOleksandr Tymoshenko
752cfe870aSOleksandr Tymoshenko device_set_desc(dev, "Simple Amplifier");
762cfe870aSOleksandr Tymoshenko return (BUS_PROBE_DEFAULT);
772cfe870aSOleksandr Tymoshenko }
782cfe870aSOleksandr Tymoshenko
792cfe870aSOleksandr Tymoshenko static int
simple_amp_attach(device_t dev)802cfe870aSOleksandr Tymoshenko simple_amp_attach(device_t dev)
812cfe870aSOleksandr Tymoshenko {
822cfe870aSOleksandr Tymoshenko struct simple_amp_softc *sc;
832cfe870aSOleksandr Tymoshenko phandle_t node;
842cfe870aSOleksandr Tymoshenko int error;
852cfe870aSOleksandr Tymoshenko
862cfe870aSOleksandr Tymoshenko sc = device_get_softc(dev);
872cfe870aSOleksandr Tymoshenko sc->dev = dev;
882cfe870aSOleksandr Tymoshenko node = ofw_bus_get_node(dev);
892cfe870aSOleksandr Tymoshenko
902cfe870aSOleksandr Tymoshenko error = gpio_pin_get_by_ofw_property(dev, node,
912cfe870aSOleksandr Tymoshenko "enable-gpios", &sc->gpio_enable);
922cfe870aSOleksandr Tymoshenko if (error != 0)
932cfe870aSOleksandr Tymoshenko sc->gpio_is_valid = false;
942cfe870aSOleksandr Tymoshenko else
952cfe870aSOleksandr Tymoshenko sc->gpio_is_valid = true;
962cfe870aSOleksandr Tymoshenko
972cfe870aSOleksandr Tymoshenko error = regulator_get_by_ofw_property(dev, 0, "VCC-supply",
982cfe870aSOleksandr Tymoshenko &sc->supply_vcc);
992cfe870aSOleksandr Tymoshenko if (error != 0)
1002cfe870aSOleksandr Tymoshenko device_printf(dev, "no VCC supply");
1012cfe870aSOleksandr Tymoshenko
1022cfe870aSOleksandr Tymoshenko OF_device_register_xref(OF_xref_from_node(node), dev);
1032cfe870aSOleksandr Tymoshenko
1042cfe870aSOleksandr Tymoshenko return (0);
1052cfe870aSOleksandr Tymoshenko }
1062cfe870aSOleksandr Tymoshenko
1072cfe870aSOleksandr Tymoshenko static int
simple_amp_detach(device_t dev)1082cfe870aSOleksandr Tymoshenko simple_amp_detach(device_t dev)
1092cfe870aSOleksandr Tymoshenko {
1102cfe870aSOleksandr Tymoshenko
1112cfe870aSOleksandr Tymoshenko return (0);
1122cfe870aSOleksandr Tymoshenko }
1132cfe870aSOleksandr Tymoshenko
1142cfe870aSOleksandr Tymoshenko static int
simple_amp_dai_init(device_t dev,uint32_t format)1152cfe870aSOleksandr Tymoshenko simple_amp_dai_init(device_t dev, uint32_t format)
1162cfe870aSOleksandr Tymoshenko {
1172cfe870aSOleksandr Tymoshenko
1182cfe870aSOleksandr Tymoshenko return (0);
1192cfe870aSOleksandr Tymoshenko }
1202cfe870aSOleksandr Tymoshenko
1212cfe870aSOleksandr Tymoshenko static int
simple_amp_dai_trigger(device_t dev,int go,int pcm_dir)1222cfe870aSOleksandr Tymoshenko simple_amp_dai_trigger(device_t dev, int go, int pcm_dir)
1232cfe870aSOleksandr Tymoshenko {
1242cfe870aSOleksandr Tymoshenko struct simple_amp_softc *sc;
1252cfe870aSOleksandr Tymoshenko int error;
1262cfe870aSOleksandr Tymoshenko
1272cfe870aSOleksandr Tymoshenko if ((pcm_dir != PCMDIR_PLAY) && (pcm_dir != PCMDIR_REC))
1282cfe870aSOleksandr Tymoshenko return (EINVAL);
1292cfe870aSOleksandr Tymoshenko
1302cfe870aSOleksandr Tymoshenko sc = device_get_softc(dev);
1312cfe870aSOleksandr Tymoshenko error = 0;
1322cfe870aSOleksandr Tymoshenko switch (go) {
1332cfe870aSOleksandr Tymoshenko case PCMTRIG_START:
1342cfe870aSOleksandr Tymoshenko if (sc->supply_vcc != NULL) {
1352cfe870aSOleksandr Tymoshenko error = regulator_enable(sc->supply_vcc);
1362cfe870aSOleksandr Tymoshenko if (error != 0) {
1372cfe870aSOleksandr Tymoshenko device_printf(sc->dev,
1382cfe870aSOleksandr Tymoshenko "could not enable 'VCC' regulator\n");
1392cfe870aSOleksandr Tymoshenko break;
1402cfe870aSOleksandr Tymoshenko }
1412cfe870aSOleksandr Tymoshenko }
1422cfe870aSOleksandr Tymoshenko
1432cfe870aSOleksandr Tymoshenko if (sc->gpio_is_valid) {
1442cfe870aSOleksandr Tymoshenko error = gpio_pin_set_active(sc->gpio_enable, 1);
1452cfe870aSOleksandr Tymoshenko if (error != 0) {
1462cfe870aSOleksandr Tymoshenko device_printf(sc->dev,
1472cfe870aSOleksandr Tymoshenko "could not set 'gpio-enable' gpio\n");
1482cfe870aSOleksandr Tymoshenko break;
1492cfe870aSOleksandr Tymoshenko }
1502cfe870aSOleksandr Tymoshenko }
1512cfe870aSOleksandr Tymoshenko
1522cfe870aSOleksandr Tymoshenko break;
1532cfe870aSOleksandr Tymoshenko
1542cfe870aSOleksandr Tymoshenko case PCMTRIG_STOP:
1552cfe870aSOleksandr Tymoshenko case PCMTRIG_ABORT:
1562cfe870aSOleksandr Tymoshenko if (sc->gpio_is_valid) {
1572cfe870aSOleksandr Tymoshenko error = gpio_pin_set_active(sc->gpio_enable, 0);
1582cfe870aSOleksandr Tymoshenko if (error != 0) {
1592cfe870aSOleksandr Tymoshenko device_printf(sc->dev,
1602cfe870aSOleksandr Tymoshenko "could not clear 'gpio-enable' gpio\n");
1612cfe870aSOleksandr Tymoshenko break;
1622cfe870aSOleksandr Tymoshenko }
1632cfe870aSOleksandr Tymoshenko }
1642cfe870aSOleksandr Tymoshenko
1652cfe870aSOleksandr Tymoshenko if (sc->supply_vcc != NULL) {
1662cfe870aSOleksandr Tymoshenko error = regulator_disable(sc->supply_vcc);
1672cfe870aSOleksandr Tymoshenko if (error != 0) {
1682cfe870aSOleksandr Tymoshenko device_printf(sc->dev,
1692cfe870aSOleksandr Tymoshenko "could not disable 'VCC' regulator\n");
1702cfe870aSOleksandr Tymoshenko break;
1712cfe870aSOleksandr Tymoshenko }
1722cfe870aSOleksandr Tymoshenko }
1732cfe870aSOleksandr Tymoshenko
1742cfe870aSOleksandr Tymoshenko break;
1752cfe870aSOleksandr Tymoshenko }
1762cfe870aSOleksandr Tymoshenko
1772cfe870aSOleksandr Tymoshenko return (error);
1782cfe870aSOleksandr Tymoshenko }
1792cfe870aSOleksandr Tymoshenko
1802cfe870aSOleksandr Tymoshenko static device_method_t simple_amp_methods[] = {
1812cfe870aSOleksandr Tymoshenko /* Device interface */
1822cfe870aSOleksandr Tymoshenko DEVMETHOD(device_probe, simple_amp_probe),
1832cfe870aSOleksandr Tymoshenko DEVMETHOD(device_attach, simple_amp_attach),
1842cfe870aSOleksandr Tymoshenko DEVMETHOD(device_detach, simple_amp_detach),
1852cfe870aSOleksandr Tymoshenko
1862cfe870aSOleksandr Tymoshenko DEVMETHOD(audio_dai_init, simple_amp_dai_init),
1872cfe870aSOleksandr Tymoshenko DEVMETHOD(audio_dai_trigger, simple_amp_dai_trigger),
1882cfe870aSOleksandr Tymoshenko
1892cfe870aSOleksandr Tymoshenko DEVMETHOD_END
1902cfe870aSOleksandr Tymoshenko };
1912cfe870aSOleksandr Tymoshenko
1922cfe870aSOleksandr Tymoshenko static driver_t simple_amp_driver = {
1932cfe870aSOleksandr Tymoshenko "simpleamp",
1942cfe870aSOleksandr Tymoshenko simple_amp_methods,
1952cfe870aSOleksandr Tymoshenko sizeof(struct simple_amp_softc),
1962cfe870aSOleksandr Tymoshenko };
1972cfe870aSOleksandr Tymoshenko
1983390adfeSJohn Baldwin DRIVER_MODULE(simple_amp, simplebus, simple_amp_driver, 0, 0);
1992cfe870aSOleksandr Tymoshenko SIMPLEBUS_PNP_INFO(compat_data);
200