The branch main has been updated by manu:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=2cfe870acdecd35b621932f2b0cb702c48ce087a

commit 2cfe870acdecd35b621932f2b0cb702c48ce087a
Author:     Oleksandr Tymoshenko <go...@freebsd.org>
AuthorDate: 2021-05-13 19:09:50 +0000
Commit:     Emmanuel Vadot <m...@freebsd.org>
CommitDate: 2021-06-11 19:06:04 +0000

    arm64: Add Soc audio framework
    
    This framework is initial implementation of the simple-audio-card compatible
    audio driver framework. It provides glue for CPU/codec/aux device.
    
    Differential Revision:  https://reviews.freebsd.org/D27830
---
 sys/conf/files.arm64                 |   8 +
 sys/dev/sound/fdt/audio_dai.h        |  72 +++++
 sys/dev/sound/fdt/audio_dai_if.m     |  95 ++++++
 sys/dev/sound/fdt/audio_soc.c        | 546 +++++++++++++++++++++++++++++++++++
 sys/dev/sound/fdt/dummy_codec.c      | 127 ++++++++
 sys/dev/sound/fdt/simple_amplifier.c | 206 +++++++++++++
 6 files changed, 1054 insertions(+)

diff --git a/sys/conf/files.arm64 b/sys/conf/files.arm64
index 7b9b2583aaa1..5c819001493d 100644
--- a/sys/conf/files.arm64
+++ b/sys/conf/files.arm64
@@ -148,6 +148,14 @@ cddl/dev/dtrace/aarch64/dtrace_asm.S               
optional dtrace compile-with "${DTRACE_S}"
 cddl/dev/dtrace/aarch64/dtrace_subr.c          optional dtrace compile-with 
"${DTRACE_C}"
 cddl/dev/fbt/aarch64/fbt_isa.c                 optional dtrace_fbt | dtraceall 
compile-with "${FBT_C}"
 
+##
+## ASoC support
+##
+dev/sound/fdt/audio_dai_if.m                   optional sound fdt
+dev/sound/fdt/audio_soc.c                      optional sound fdt
+dev/sound/fdt/dummy_codec.c                    optional sound fdt
+dev/sound/fdt/simple_amplifier.c               optional sound fdt
+
 ##
 ## Device drivers
 ##
diff --git a/sys/dev/sound/fdt/audio_dai.h b/sys/dev/sound/fdt/audio_dai.h
new file mode 100644
index 000000000000..f82fe9c7b838
--- /dev/null
+++ b/sys/dev/sound/fdt/audio_dai.h
@@ -0,0 +1,72 @@
+/*-
+ * Copyright (c) 2019 Oleksandr Tymoshenko <go...@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef __DAI_H__
+#define __DAI_H__
+
+#define        AUDIO_DAI_FORMAT_I2S            0
+#define        AUDIO_DAI_FORMAT_RJ             1
+#define        AUDIO_DAI_FORMAT_LJ             2
+#define        AUDIO_DAI_FORMAT_DSPA           3
+#define        AUDIO_DAI_FORMAT_DSPB           4
+#define        AUDIO_DAI_FORMAT_AC97           5
+#define        AUDIO_DAI_FORMAT_PDM            6
+
+/*
+ * Polarity: Normal/Inverted BCLK/Frame
+ */
+#define        AUDIO_DAI_POLARITY_NB_NF        0
+#define        AUDIO_DAI_POLARITY_NB_IF        1
+#define        AUDIO_DAI_POLARITY_IB_NF        2
+#define        AUDIO_DAI_POLARITY_IB_IF        3
+#define        AUDIO_DAI_POLARITY_INVERTED_FRAME(n)    ((n) & 0x01)
+#define        AUDIO_DAI_POLARITY_INVERTED_BCLK(n)     ((n) & 0x2)
+
+#define        AUDIO_DAI_CLOCK_CBM_CFM         0
+#define        AUDIO_DAI_CLOCK_CBS_CFM         1
+#define        AUDIO_DAI_CLOCK_CBM_CFS         2
+#define        AUDIO_DAI_CLOCK_CBS_CFS         3
+
+#define        AUDIO_DAI_CLOCK_IN              0
+#define        AUDIO_DAI_CLOCK_OUT             1
+
+#define        AUDIO_DAI_JACK_HP               0
+#define        AUDIO_DAI_JACK_MIC              1
+
+/*
+ * Signal to audio_soc that chn_intr required
+ * for either recording or playback
+ */
+#define        AUDIO_DAI_REC_INTR              (1 << 1)
+#define        AUDIO_DAI_PLAY_INTR             (1 << 0)
+
+#define        AUDIO_DAI_FORMAT(fmt, pol, clk)         (((fmt) << 16) | ((pol) 
<< 8) | (clk))
+#define        AUDIO_DAI_FORMAT_FORMAT(format)         (((format) >> 16) & 
0xff)
+#define        AUDIO_DAI_FORMAT_POLARITY(format)       (((format) >> 8) & 0xff)
+#define        AUDIO_DAI_FORMAT_CLOCK(format)          (((format) >> 0) & 0xff)
+
+
+#endif /* __DAI_H__ */
diff --git a/sys/dev/sound/fdt/audio_dai_if.m b/sys/dev/sound/fdt/audio_dai_if.m
new file mode 100644
index 000000000000..dc3ebbba5489
--- /dev/null
+++ b/sys/dev/sound/fdt/audio_dai_if.m
@@ -0,0 +1,95 @@
+#-
+# Copyright (c) 2019 Oleksandr Tymoshenko <go...@freebsd.org>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+# $FreeBSD$
+#
+
+CODE {
+       #include <sys/param.h>
+       #include <sys/bus.h>
+       #include <dev/sound/pcm/sound.h>
+}
+
+INTERFACE audio_dai;
+
+# set DAI format for communications between CPU/codec nodes
+METHOD int init {
+       device_t        dev;
+       uint32_t        format;
+}
+
+# Initialize DAI and set up interrrupt handler
+METHOD int setup_intr {
+       device_t        dev;
+       driver_intr_t   intr_handler;
+       void            *intr_arg;
+}
+
+# Setup mixers for codec node
+METHOD int setup_mixer {
+       device_t        dev;
+       device_t        ausocdev;
+}
+
+# setup clock speed
+METHOD int set_sysclk {
+       device_t        dev;
+       uint32_t        rate;
+       int             dai_dir;
+}
+
+METHOD int trigger {
+       device_t        dev;
+       int             go;
+       int             pcm_dir;
+}
+
+METHOD struct pcmchan_caps* get_caps {
+       device_t        dev;
+}
+
+METHOD uint32_t get_ptr {
+       device_t        dev;
+       int             pcm_dir;
+}
+
+# Set PCM channel format
+METHOD uint32_t set_chanformat {
+       device_t        dev;
+       uint32_t        format;
+}
+
+# Set PCM channel sampling rate
+METHOD uint32_t set_chanspeed {
+       device_t        dev;
+       uint32_t        speed;
+}
+
+# call DAI interrupt handler
+# returns 1 if call to chn_intr required, 0 otherwise
+METHOD int intr {
+       device_t        dev;
+       struct snd_dbuf *play_buf;
+       struct snd_dbuf *rec_buf;
+}
diff --git a/sys/dev/sound/fdt/audio_soc.c b/sys/dev/sound/fdt/audio_soc.c
new file mode 100644
index 000000000000..cd5807d955c9
--- /dev/null
+++ b/sys/dev/sound/fdt/audio_soc.c
@@ -0,0 +1,546 @@
+/*-
+ * Copyright (c) 2019 Oleksandr Tymoshenko <go...@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include "opt_platform.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/clock.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/endian.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/sound/fdt/audio_dai.h>
+#include <dev/sound/pcm/sound.h>
+#include "audio_dai_if.h"
+
+#define        AUDIO_BUFFER_SIZE       48000 * 4
+
+struct audio_soc_aux_node {
+       SLIST_ENTRY(audio_soc_aux_node) link;
+       device_t                        dev;
+};
+
+struct audio_soc_channel {
+       struct audio_soc_softc  *sc;    /* parent device's softc */
+       struct pcm_channel      *pcm;   /* PCM channel */
+       struct snd_dbuf         *buf;   /* PCM buffer */
+       int                     dir;    /* direction */
+};
+
+struct audio_soc_softc {
+       /*
+        * pcm_register assumes that sc is snddev_info,
+        * so this has to be first structure member for "compatiblity"
+        */
+       struct snddev_info      info;
+       device_t                dev;
+       char                    *name;
+       struct intr_config_hook init_hook;
+       device_t                cpu_dev;
+       device_t                codec_dev;
+       SLIST_HEAD(, audio_soc_aux_node)        aux_devs;
+       unsigned int            mclk_fs;
+       struct audio_soc_channel        play_channel;
+       struct audio_soc_channel        rec_channel;
+       /*
+        * The format is from the CPU node, for CODEC node clock roles
+        * need to be reversed.
+        */
+       uint32_t                format;
+       uint32_t                link_mclk_fs;
+};
+
+static struct ofw_compat_data compat_data[] = {
+       {"simple-audio-card",   1},
+       {NULL,                  0},
+};
+
+static struct {
+       const char *name;
+       unsigned int fmt;
+} ausoc_dai_formats[] = {
+       { "i2s",        AUDIO_DAI_FORMAT_I2S },
+       { "right_j",    AUDIO_DAI_FORMAT_RJ },
+       { "left_j",     AUDIO_DAI_FORMAT_LJ },
+       { "dsp_a",      AUDIO_DAI_FORMAT_DSPA },
+       { "dsp_b",      AUDIO_DAI_FORMAT_DSPB },
+       { "ac97",       AUDIO_DAI_FORMAT_AC97 },
+       { "pdm",        AUDIO_DAI_FORMAT_PDM },
+};
+
+static int     audio_soc_probe(device_t dev);
+static int     audio_soc_attach(device_t dev);
+static int     audio_soc_detach(device_t dev);
+
+/*
+ * Invert master/slave roles for CODEC side of the node
+ */
+static uint32_t
+audio_soc_reverse_clocks(uint32_t format)
+{
+       int fmt, pol, clk;
+
+       fmt = AUDIO_DAI_FORMAT_FORMAT(format);
+       pol = AUDIO_DAI_FORMAT_POLARITY(format);
+       clk = AUDIO_DAI_FORMAT_CLOCK(format);
+
+       switch (clk) {
+       case AUDIO_DAI_CLOCK_CBM_CFM:
+               clk = AUDIO_DAI_CLOCK_CBS_CFS;
+               break;
+       case AUDIO_DAI_CLOCK_CBS_CFM:
+               clk = AUDIO_DAI_CLOCK_CBM_CFS;
+               break;
+       case AUDIO_DAI_CLOCK_CBM_CFS:
+               clk = AUDIO_DAI_CLOCK_CBS_CFM;
+               break;
+       case AUDIO_DAI_CLOCK_CBS_CFS:
+               clk = AUDIO_DAI_CLOCK_CBM_CFM;
+               break;
+       }
+
+       return AUDIO_DAI_FORMAT(fmt, pol, clk);
+}
+
+static uint32_t
+audio_soc_chan_setblocksize(kobj_t obj, void *data, uint32_t blocksz)
+{
+
+       return (blocksz);
+}
+
+static int
+audio_soc_chan_setformat(kobj_t obj, void *data, uint32_t format)
+{
+
+       struct audio_soc_softc *sc;
+       struct audio_soc_channel *ausoc_chan;
+
+       ausoc_chan = data;
+       sc = ausoc_chan->sc;
+
+       return AUDIO_DAI_SET_CHANFORMAT(sc->cpu_dev, format);
+}
+
+static uint32_t
+audio_soc_chan_setspeed(kobj_t obj, void *data, uint32_t speed)
+{
+
+       struct audio_soc_softc *sc;
+       struct audio_soc_channel *ausoc_chan;
+       uint32_t rate;
+       struct audio_soc_aux_node *aux_node;
+
+       ausoc_chan = data;
+       sc = ausoc_chan->sc;
+
+       if (sc->link_mclk_fs) {
+               rate = speed * sc->link_mclk_fs;
+               if (AUDIO_DAI_SET_SYSCLK(sc->cpu_dev, rate, AUDIO_DAI_CLOCK_IN))
+                       device_printf(sc->dev, "failed to set sysclk for CPU 
node\n");
+
+               if (AUDIO_DAI_SET_SYSCLK(sc->codec_dev, rate, 
AUDIO_DAI_CLOCK_OUT))
+                       device_printf(sc->dev, "failed to set sysclk for codec 
node\n");
+
+               SLIST_FOREACH(aux_node, &sc->aux_devs, link) {
+                       if (AUDIO_DAI_SET_SYSCLK(aux_node->dev, rate, 
AUDIO_DAI_CLOCK_OUT))
+                               device_printf(sc->dev, "failed to set sysclk 
for aux node\n");
+               }
+       }
+
+       /*
+        * Let CPU node determine speed
+        */
+       speed = AUDIO_DAI_SET_CHANSPEED(sc->cpu_dev, speed);
+       AUDIO_DAI_SET_CHANSPEED(sc->codec_dev, speed);
+       SLIST_FOREACH(aux_node, &sc->aux_devs, link) {
+               AUDIO_DAI_SET_CHANSPEED(aux_node->dev, speed);
+       }
+
+       return (speed);
+}
+
+static uint32_t
+audio_soc_chan_getptr(kobj_t obj, void *data)
+{
+       struct audio_soc_softc *sc;
+       struct audio_soc_channel *ausoc_chan;
+
+       ausoc_chan = data;
+       sc = ausoc_chan->sc;
+
+       return AUDIO_DAI_GET_PTR(sc->cpu_dev, ausoc_chan->dir);
+}
+
+static void *
+audio_soc_chan_init(kobj_t obj, void *devinfo, struct snd_dbuf *b,
+       struct pcm_channel *c, int dir)
+{
+       struct audio_soc_softc *sc;
+       struct audio_soc_channel *ausoc_chan;
+       void *buffer;
+
+       ausoc_chan = devinfo;
+       sc = ausoc_chan->sc;
+       buffer = malloc(AUDIO_BUFFER_SIZE, M_DEVBUF, M_WAITOK | M_ZERO);
+
+       if (sndbuf_setup(b, buffer, AUDIO_BUFFER_SIZE) != 0) {
+               free(buffer, M_DEVBUF);
+               return NULL;
+       }
+
+       ausoc_chan->dir = dir;
+       ausoc_chan->buf = b;
+       ausoc_chan->pcm = c;
+
+       return (devinfo);
+}
+
+static int
+audio_soc_chan_trigger(kobj_t obj, void *data, int go)
+{
+       struct audio_soc_softc *sc;
+       struct audio_soc_channel *ausoc_chan;
+       struct audio_soc_aux_node *aux_node;
+
+       ausoc_chan = (struct audio_soc_channel *)data;
+       sc = ausoc_chan->sc;
+       AUDIO_DAI_TRIGGER(sc->codec_dev, go, ausoc_chan->dir);
+       SLIST_FOREACH(aux_node, &sc->aux_devs, link) {
+               AUDIO_DAI_TRIGGER(aux_node->dev, go, ausoc_chan->dir);
+       }
+
+       return AUDIO_DAI_TRIGGER(sc->cpu_dev, go, ausoc_chan->dir);
+}
+
+static int
+audio_soc_chan_free(kobj_t obj, void *data)
+{
+
+       struct audio_soc_softc *sc;
+       struct audio_soc_channel *ausoc_chan;
+       void *buffer;
+
+       ausoc_chan = (struct audio_soc_channel *)data;
+       sc = ausoc_chan->sc;
+
+       buffer = sndbuf_getbuf(ausoc_chan->buf);
+       if (buffer)
+               free(buffer, M_DEVBUF);
+
+       return (0);
+}
+
+static struct pcmchan_caps *
+audio_soc_chan_getcaps(kobj_t obj, void *data)
+{
+       struct audio_soc_softc *sc;
+       struct audio_soc_channel *ausoc_chan;
+
+       ausoc_chan = data;
+       sc = ausoc_chan->sc;
+
+       return AUDIO_DAI_GET_CAPS(sc->cpu_dev);
+}
+
+static kobj_method_t audio_soc_chan_methods[] = {
+       KOBJMETHOD(channel_init,        audio_soc_chan_init),
+       KOBJMETHOD(channel_free,        audio_soc_chan_free),
+       KOBJMETHOD(channel_setformat,   audio_soc_chan_setformat),
+       KOBJMETHOD(channel_setspeed,    audio_soc_chan_setspeed),
+       KOBJMETHOD(channel_setblocksize,audio_soc_chan_setblocksize),
+       KOBJMETHOD(channel_trigger,     audio_soc_chan_trigger),
+       KOBJMETHOD(channel_getptr,      audio_soc_chan_getptr),
+       KOBJMETHOD(channel_getcaps,     audio_soc_chan_getcaps),
+       KOBJMETHOD_END
+};
+CHANNEL_DECLARE(audio_soc_chan);
+
+static void
+audio_soc_intr(void *arg)
+{
+       struct audio_soc_softc *sc;
+       int channel_intr_required;
+
+       sc = (struct audio_soc_softc *)arg;
+       channel_intr_required = AUDIO_DAI_INTR(sc->cpu_dev, 
sc->play_channel.buf, sc->rec_channel.buf);
+       if (channel_intr_required & AUDIO_DAI_PLAY_INTR)
+               chn_intr(sc->play_channel.pcm);
+       if (channel_intr_required & AUDIO_DAI_REC_INTR)
+               chn_intr(sc->rec_channel.pcm);
+}
+
+static int
+audio_soc_probe(device_t dev)
+{
+
+       if (!ofw_bus_status_okay(dev))
+               return (ENXIO);
+
+       if (ofw_bus_search_compatible(dev, compat_data)->ocd_data != 0) {
+               device_set_desc(dev, "simple-audio-card");
+               return (BUS_PROBE_DEFAULT);
+       }
+
+       return (ENXIO);
+}
+
+static void
+audio_soc_init(void *arg)
+{
+       struct audio_soc_softc *sc;
+       phandle_t node, child;
+       device_t daidev, auxdev;
+       uint32_t xref;
+       uint32_t *aux_devs;
+       int ncells, i;
+       struct audio_soc_aux_node *aux_node;
+
+       sc = (struct audio_soc_softc *)arg;
+       config_intrhook_disestablish(&sc->init_hook);
+
+       node = ofw_bus_get_node(sc->dev);
+       /* TODO: handle multi-link nodes */
+       child = ofw_bus_find_child(node, "simple-audio-card,cpu");
+       if (child == 0) {
+               device_printf(sc->dev, "cpu node is missing\n");
+               return;
+       }
+       if ((OF_getencprop(child, "sound-dai", &xref, sizeof(xref))) <= 0) {
+               device_printf(sc->dev, "missing sound-dai property in cpu 
node\n");
+               return;
+       }
+       daidev = OF_device_from_xref(xref);
+       if (daidev == NULL) {
+               device_printf(sc->dev, "no driver attached to cpu node\n");
+               return;
+       }
+       sc->cpu_dev = daidev;
+
+       child = ofw_bus_find_child(node, "simple-audio-card,codec");
+       if (child == 0) {
+               device_printf(sc->dev, "codec node is missing\n");
+               return;
+       }
+       if ((OF_getencprop(child, "sound-dai", &xref, sizeof(xref))) <= 0) {
+               device_printf(sc->dev, "missing sound-dai property in codec 
node\n");
+               return;
+       }
+       daidev = OF_device_from_xref(xref);
+       if (daidev == NULL) {
+               device_printf(sc->dev, "no driver attached to codec node\n");
+               return;
+       }
+       sc->codec_dev = daidev;
+
+       /* Add AUX devices */
+       aux_devs = NULL;
+       ncells = OF_getencprop_alloc_multi(node, "simple-audio-card,aux-devs", 
sizeof(*aux_devs),
+           (void **)&aux_devs);
+
+       for (i = 0; i < ncells; i++) {
+               auxdev = OF_device_from_xref(aux_devs[i]);
+               if (auxdev == NULL)
+                       device_printf(sc->dev, "warning: no driver attached to 
aux node\n");
+               aux_node = (struct audio_soc_aux_node 
*)malloc(sizeof(*aux_node), M_DEVBUF, M_NOWAIT);
+               if (aux_node == NULL) {
+                       device_printf(sc->dev, "failed to allocate aux node 
struct\n");
+                       return;
+               }
+               aux_node->dev = auxdev;
+               SLIST_INSERT_HEAD(&sc->aux_devs, aux_node, link);
+       }
+
+       if (aux_devs)
+               OF_prop_free(aux_devs);
+
+       if (AUDIO_DAI_INIT(sc->cpu_dev, sc->format)) {
+               device_printf(sc->dev, "failed to initialize cpu node\n");
+               return;
+       }
+
+       /* Reverse clock roles for CODEC */
+       if (AUDIO_DAI_INIT(sc->codec_dev, 
audio_soc_reverse_clocks(sc->format))) {
+               device_printf(sc->dev, "failed to initialize codec node\n");
+               return;
+       }
+
+       SLIST_FOREACH(aux_node, &sc->aux_devs, link) {
+               if (AUDIO_DAI_INIT(aux_node->dev, 
audio_soc_reverse_clocks(sc->format))) {
+                       device_printf(sc->dev, "failed to initialize aux 
node\n");
+                       return;
+               }
+       }
+
+       if (pcm_register(sc->dev, sc, 1, 1)) {
+               device_printf(sc->dev, "failed to register PCM\n");
+               return;
+       }
+
+       pcm_getbuffersize(sc->dev, AUDIO_BUFFER_SIZE, AUDIO_BUFFER_SIZE,
+           AUDIO_BUFFER_SIZE);
+       sc->play_channel.sc = sc;
+       sc->rec_channel.sc = sc;
+
+       pcm_addchan(sc->dev, PCMDIR_PLAY, &audio_soc_chan_class, 
&sc->play_channel);
+       pcm_addchan(sc->dev, PCMDIR_REC, &audio_soc_chan_class, 
&sc->rec_channel);
+
+       pcm_setstatus(sc->dev, "at EXPERIMENT");
+
+       AUDIO_DAI_SETUP_INTR(sc->cpu_dev, audio_soc_intr, sc);
+       AUDIO_DAI_SETUP_MIXER(sc->codec_dev, sc->dev);
+       SLIST_FOREACH(aux_node, &sc->aux_devs, link) {
+               AUDIO_DAI_SETUP_MIXER(aux_node->dev, sc->dev);
+       }
+}
+
+static int
+audio_soc_attach(device_t dev)
+{
+       struct audio_soc_softc *sc;
+       char *name;
+       phandle_t node, cpu_child;
+       uint32_t xref;
+       int i, ret;
+       char tmp[32];
+       unsigned int fmt, pol, clk;
+       bool frame_master, bitclock_master;
+
+       sc = device_get_softc(dev);
+       sc->dev = dev;
+       node = ofw_bus_get_node(dev);
+
+       ret = OF_getprop_alloc(node, "name", (void **)&name);
+       if (ret == -1)
+               name = "SoC audio";
+
+       sc->name = strdup(name, M_DEVBUF);
+       device_set_desc(dev, sc->name);
+
+       if (ret != -1)
+               OF_prop_free(name);
+
+       SLIST_INIT(&sc->aux_devs);
+
+       ret = OF_getprop(node, "simple-audio-card,format", tmp, sizeof(tmp));
+       if (ret == 0) {
+               for (i = 0; i < nitems(ausoc_dai_formats); i++) {
+                       if (strcmp(tmp, ausoc_dai_formats[i].name) == 0) {
+                               fmt = ausoc_dai_formats[i].fmt;
+                               break;
+                       }
+               }
+               if (i == nitems(ausoc_dai_formats))
+                       return (EINVAL);
+       } else
+               fmt = AUDIO_DAI_FORMAT_I2S;
+
+       if (OF_getencprop(node, "simple-audio-card,mclk-fs",
+           &sc->link_mclk_fs, sizeof(sc->link_mclk_fs)) <= 0)
+               sc->link_mclk_fs = 0;
+
+       /* Unless specified otherwise, CPU node is the master */
+       frame_master = bitclock_master = true;
+
+       cpu_child = ofw_bus_find_child(node, "simple-audio-card,cpu");
+
+       if ((OF_getencprop(node, "simple-audio-card,frame-master", &xref, 
sizeof(xref))) > 0)
+               frame_master = cpu_child == OF_node_from_xref(xref);
+
+       if ((OF_getencprop(node, "simple-audio-card,bitclock-master", &xref, 
sizeof(xref))) > 0)
+               bitclock_master = cpu_child == OF_node_from_xref(xref);
+
+       if (frame_master) {
+               clk = bitclock_master ?
+                   AUDIO_DAI_CLOCK_CBM_CFM : AUDIO_DAI_CLOCK_CBS_CFM;
+       } else {
+               clk = bitclock_master ?
+                   AUDIO_DAI_CLOCK_CBM_CFS : AUDIO_DAI_CLOCK_CBS_CFS;
+       }
+
+       bool bitclock_inversion = OF_hasprop(node, 
"simple-audio-card,bitclock-inversion");
+       bool frame_inversion = OF_hasprop(node, 
"simple-audio-card,frame-inversion");
+       if (bitclock_inversion) {
+               pol = frame_inversion ?
+                   AUDIO_DAI_POLARITY_IB_IF : AUDIO_DAI_POLARITY_IB_NF;
+       } else {
+               pol = frame_inversion ?
+                   AUDIO_DAI_POLARITY_NB_IF : AUDIO_DAI_POLARITY_NB_NF;
+       }
+
+       sc->format = AUDIO_DAI_FORMAT(fmt, pol, clk);
+
+       sc->init_hook.ich_func = audio_soc_init;
+       sc->init_hook.ich_arg = sc;
+       if (config_intrhook_establish(&sc->init_hook) != 0)
+               return (ENOMEM);
+
+       return (0);
+}
+
+static int
+audio_soc_detach(device_t dev)
+{
+       struct audio_soc_softc *sc;
+       struct audio_soc_aux_node *aux;
+
+       sc = device_get_softc(dev);
+       if (sc->name)
+               free(sc->name, M_DEVBUF);
+
+       while ((aux = SLIST_FIRST(&sc->aux_devs)) != NULL) {
+               SLIST_REMOVE_HEAD(&sc->aux_devs, link);
+               free(aux, M_DEVBUF);
+       }
+
+       return (0);
+}
+
+static device_method_t audio_soc_methods[] = {
+        /* device_if methods */
+       DEVMETHOD(device_probe,         audio_soc_probe),
+       DEVMETHOD(device_attach,        audio_soc_attach),
+       DEVMETHOD(device_detach,        audio_soc_detach),
+
+       DEVMETHOD_END,
+};
+
+static driver_t audio_soc_driver = {
+       "pcm",
+       audio_soc_methods,
+       sizeof(struct audio_soc_softc),
+};
+
+DRIVER_MODULE(audio_soc, simplebus, audio_soc_driver, pcm_devclass, NULL, 
NULL);
+MODULE_VERSION(audio_soc, 1);
diff --git a/sys/dev/sound/fdt/dummy_codec.c b/sys/dev/sound/fdt/dummy_codec.c
new file mode 100644
index 000000000000..6be2491a069d
--- /dev/null
+++ b/sys/dev/sound/fdt/dummy_codec.c
@@ -0,0 +1,127 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Oleksandr Tymoshenko <go...@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/resource.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "opt_snd.h"
+#include <dev/sound/pcm/sound.h>
+#include <dev/sound/fdt/audio_dai.h>
+#include "audio_dai_if.h"
+
+static struct ofw_compat_data compat_data[] = {
+       { "dummy-codec",        1},
+       { NULL,                 0 }
+};
+
+struct dummy_codec_softc {
+       device_t        dev;
+};
+
+static int dummy_codec_probe(device_t dev);
+static int dummy_codec_attach(device_t dev);
+static int dummy_codec_detach(device_t dev);
+
+static int
+dummy_codec_probe(device_t dev)
+{
+       if (!ofw_bus_status_okay(dev))
+               return (ENXIO);
+
+       if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
+               return (ENXIO);
+
+       device_set_desc(dev, "Dummy Codec");
+       return (BUS_PROBE_DEFAULT);
+}
+
+static int
+dummy_codec_attach(device_t dev)
+{
+       struct dummy_codec_softc *sc;
+       phandle_t node;
+
+       sc = device_get_softc(dev);
+       sc->dev = dev;
+
+       node = ofw_bus_get_node(dev);
+       OF_device_register_xref(OF_xref_from_node(node), dev);
+
+       return (0);
+}
+
+static int
+dummy_codec_detach(device_t dev)
+{
+
+       return (0);
+}
+
+static int
+dummy_codec_dai_init(device_t dev, uint32_t format)
+{
+
+       return (0);
+}
+
+static device_method_t dummy_codec_methods[] = {
+       /* Device interface */
+       DEVMETHOD(device_probe,         dummy_codec_probe),
+       DEVMETHOD(device_attach,        dummy_codec_attach),
+       DEVMETHOD(device_detach,        dummy_codec_detach),
+
+       DEVMETHOD(audio_dai_init,       dummy_codec_dai_init),
+
+       DEVMETHOD_END
+};
+
+static driver_t dummy_codec_driver = {
+       "dummycodec",
+       dummy_codec_methods,
+       sizeof(struct dummy_codec_softc),
+};
+
+static devclass_t dummy_codec_devclass;
+
+DRIVER_MODULE(dummy_codec, simplebus, dummy_codec_driver, 
dummy_codec_devclass, 0, 0);
+SIMPLEBUS_PNP_INFO(compat_data);
diff --git a/sys/dev/sound/fdt/simple_amplifier.c 
b/sys/dev/sound/fdt/simple_amplifier.c
new file mode 100644
index 000000000000..a0531914d9be
--- /dev/null
+++ b/sys/dev/sound/fdt/simple_amplifier.c
@@ -0,0 +1,206 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+ *
+ * Copyright (c) 2020 Oleksandr Tymoshenko <go...@freebsd.org>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/rman.h>
+#include <sys/resource.h>
+#include <machine/bus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <dev/extres/regulator/regulator.h>
+#include <dev/gpio/gpiobusvar.h>
+
+#include "opt_snd.h"
+#include <dev/sound/pcm/sound.h>
+#include <dev/sound/fdt/audio_dai.h>
+#include "audio_dai_if.h"
+
+static struct ofw_compat_data compat_data[] = {
+       { "simple-audio-amplifier",     1},
+       { NULL,                         0}
+};
+
+struct simple_amp_softc {
+       device_t        dev;
+       regulator_t     supply_vcc;
+       gpio_pin_t      gpio_enable;
+       bool            gpio_is_valid;
+};
+
+static int simple_amp_probe(device_t dev);
+static int simple_amp_attach(device_t dev);
+static int simple_amp_detach(device_t dev);
+
+static int
+simple_amp_probe(device_t dev)
+{
*** 133 LINES SKIPPED ***
_______________________________________________
dev-commits-src-main@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/dev-commits-src-main
To unsubscribe, send any mail to "dev-commits-src-main-unsubscr...@freebsd.org"

Reply via email to