-/* $OpenBSD: aplaudio.c,v 1.2 2022/08/05 13:25:43 kettenis Exp $ */
+/* $OpenBSD: aplaudio.c,v 1.3 2022/09/02 17:54:42 kettenis Exp $ */
/*
* Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
* Copyright (c) 2020 Patrick Wildt <patrick@blueri.se>
uint32_t sc_mclk_fs;
struct dai_device *sc_dai_cpu;
- struct dai_device *sc_dai_codec;
+ struct dai_device *sc_dai_codec[6];
};
void aplaudio_set_format(struct aplaudio_softc *, uint32_t,
uint32_t, uint32_t);
+void aplaudio_set_tdm_slots(struct aplaudio_softc *);
int aplaudio_open(void *, int);
void aplaudio_close(void *);
struct fdt_attach_args *faa = aux;
uint32_t fmt, pol, clk;
uint32_t node, cpu, codec;
- uint32_t phandle;
+ uint32_t *dais;
char status[32];
+ int count = 0;
+ int i, ncells;
+ int len;
printf("\n");
if (codec == 0)
continue;
- phandle = 0;
- OF_getpropintarray(codec, "sound-dai",
- &phandle, sizeof(phandle));
+ len = OF_getproplen(codec, "sound-dai");
+ if (len < 0)
+ continue;
+
+ dais = malloc(len, M_TEMP, M_WAITOK);
+ OF_getpropintarray(codec, "sound-dai", dais, len);
+
+ ncells = len / sizeof(uint32_t);
+ ncells = MIN(ncells, nitems(sc->sc_dai_codec));
+ for (i = 0; i < ncells; i++) {
+ sc->sc_dai_codec[i] = dai_byphandle(dais[i]);
+ if (sc->sc_dai_codec[i] == NULL)
+ continue;
+ count++;
+ }
+
+ free(dais, M_TEMP, len);
- sc->sc_dai_codec = dai_byphandle(phandle);
- if (sc->sc_dai_codec == NULL)
+ if (count == 0)
continue;
+ if (count > 1)
+ aplaudio_set_tdm_slots(sc);
sc->sc_mclk_fs = OF_getpropint(node, "mclk-fs", 0);
aplaudio_set_format(struct aplaudio_softc *sc, uint32_t fmt, uint32_t pol,
uint32_t clk)
{
+ struct dai_device *dai;
+ int i;
+
if (sc->sc_dai_cpu->dd_set_format)
sc->sc_dai_cpu->dd_set_format(sc->sc_dai_cpu->dd_cookie,
fmt, pol, clk);
- if (sc->sc_dai_codec->dd_set_format)
- sc->sc_dai_codec->dd_set_format(sc->sc_dai_codec->dd_cookie,
- fmt, pol, clk);
+ for (i = 0; i < nitems(sc->sc_dai_codec); i++) {
+ dai = sc->sc_dai_codec[i];
+ if (dai == NULL)
+ continue;
+ if (dai->dd_set_format)
+ dai->dd_set_format(dai->dd_cookie, fmt, pol, clk);
+ }
+}
+
+void
+aplaudio_set_tdm_slots(struct aplaudio_softc *sc)
+{
+ struct dai_device *dai;
+ int i;
+
+ for (i = 0; i < nitems(sc->sc_dai_codec); i++) {
+ dai = sc->sc_dai_codec[i];
+ if (dai == NULL)
+ continue;
+ if (dai->dd_set_tdm_slot)
+ dai->dd_set_tdm_slot(dai->dd_cookie, i % 2);
+ }
}
int
struct dai_device *dai;
const struct audio_hw_if *hwif;
int error;
+ int i;
dai = sc->sc_dai_cpu;
hwif = dai->dd_hw_if;
}
}
- dai = sc->sc_dai_codec;
- hwif = dai->dd_hw_if;
- if (hwif->open) {
- error = hwif->open(dai->dd_cookie, flags);
- if (error) {
- aplaudio_close(cookie);
- return error;
+ for (i = 0; i < nitems(sc->sc_dai_codec); i++) {
+ dai = sc->sc_dai_codec[i];
+ if (dai == NULL)
+ continue;
+ hwif = dai->dd_hw_if;
+ if (hwif->open) {
+ error = hwif->open(dai->dd_cookie, flags);
+ if (error) {
+ aplaudio_close(cookie);
+ return error;
+ }
}
}
struct aplaudio_softc *sc = cookie;
struct dai_device *dai;
const struct audio_hw_if *hwif;
+ int i;
- dai = sc->sc_dai_codec;
- hwif = dai->dd_hw_if;
- if (hwif->close)
- hwif->close(dai->dd_cookie);
+ for (i = 0; i < nitems(sc->sc_dai_codec); i++) {
+ dai = sc->sc_dai_codec[i];
+ if (dai == NULL)
+ continue;
+ hwif = dai->dd_hw_if;
+ if (hwif->close)
+ hwif->close(dai->dd_cookie);
+ }
dai = sc->sc_dai_cpu;
hwif = dai->dd_hw_if;
const struct audio_hw_if *hwif;
uint32_t rate;
int error;
+ int i;
if (sc->sc_mclk_fs) {
if (setmode & AUMODE_PLAY)
else
rate = rec->sample_rate * sc->sc_mclk_fs;
- dai = sc->sc_dai_codec;
- if (dai->dd_set_sysclk) {
- error = dai->dd_set_sysclk(dai->dd_cookie, rate);
- if (error)
- return error;
+ for (i = 0; i < nitems(sc->sc_dai_codec); i++) {
+ dai = sc->sc_dai_codec[i];
+ if (dai == NULL)
+ continue;
+ if (dai->dd_set_sysclk) {
+ error = dai->dd_set_sysclk(dai->dd_cookie, rate);
+ if (error)
+ return error;
+ }
}
dai = sc->sc_dai_cpu;
return error;
}
- dai = sc->sc_dai_codec;
- hwif = dai->dd_hw_if;
- if (hwif->set_params) {
- error = hwif->set_params(dai->dd_cookie,
- setmode, usemode, play, rec);
- if (error)
- return error;
- }
-
return 0;
}
aplaudio_set_port(void *cookie, mixer_ctrl_t *cp)
{
struct aplaudio_softc *sc = cookie;
- struct dai_device *dai = sc->sc_dai_codec;
- const struct audio_hw_if *hwif = dai->dd_hw_if;
+ struct dai_device *dai;
+ const struct audio_hw_if *hwif;
+ int error = ENXIO;
+ int i;
- if (hwif->set_port)
- return hwif->set_port(dai->dd_cookie, cp);
+ for (i = 0; i < nitems(sc->sc_dai_codec); i++) {
+ dai = sc->sc_dai_codec[i];
+ if (dai == NULL)
+ continue;
+ hwif = dai->dd_hw_if;
+ if (hwif->set_port)
+ error = hwif->set_port(dai->dd_cookie, cp);
+ }
- return ENXIO;
+ return error;
}
int
aplaudio_get_port(void *cookie, mixer_ctrl_t *cp)
{
struct aplaudio_softc *sc = cookie;
- struct dai_device *dai = sc->sc_dai_codec;
- const struct audio_hw_if *hwif = dai->dd_hw_if;
+ struct dai_device *dai;
+ const struct audio_hw_if *hwif;
+ int error = ENXIO;
+ int i;
- if (hwif->get_port)
- return hwif->get_port(dai->dd_cookie, cp);
+ for (i = 0; i < nitems(sc->sc_dai_codec); i++) {
+ dai = sc->sc_dai_codec[i];
+ if (dai == NULL)
+ continue;
+ hwif = dai->dd_hw_if;
+ if (hwif->get_port)
+ error = hwif->get_port(dai->dd_cookie, cp);
+ }
- return ENXIO;
+ return error;
}
int
aplaudio_query_devinfo(void *cookie, mixer_devinfo_t *dip)
{
struct aplaudio_softc *sc = cookie;
- struct dai_device *dai = sc->sc_dai_codec;
- const struct audio_hw_if *hwif = dai->dd_hw_if;
+ struct dai_device *dai;
+ const struct audio_hw_if *hwif;
+ int i;
- if (hwif->query_devinfo)
- return hwif->query_devinfo(dai->dd_cookie, dip);
+ for (i = 0; i < nitems(sc->sc_dai_codec); i++) {
+ dai = sc->sc_dai_codec[i];
+ if (dai == NULL)
+ continue;
+ hwif = dai->dd_hw_if;
+ if (hwif->query_devinfo)
+ return hwif->query_devinfo(dai->dd_cookie, dip);
+ }
return ENXIO;
}
struct dai_device *dai;
const struct audio_hw_if *hwif;
int error;
+ int i;
- dai = sc->sc_dai_codec;
- hwif = dai->dd_hw_if;
- if (hwif->trigger_output) {
- error = hwif->trigger_output(dai->dd_cookie,
- start, end, blksize, intr, arg, param);
- if (error) {
- aplaudio_halt_output(cookie);
- return error;
+ for (i = 0; i < nitems(sc->sc_dai_codec); i++) {
+ dai = sc->sc_dai_codec[i];
+ if (dai == NULL)
+ continue;
+ hwif = dai->dd_hw_if;
+ if (hwif->trigger_output) {
+ error = hwif->trigger_output(dai->dd_cookie,
+ start, end, blksize, intr, arg, param);
+ if (error) {
+ aplaudio_halt_output(cookie);
+ return error;
+ }
}
}
struct dai_device *dai;
const struct audio_hw_if *hwif;
int error;
+ int i;
- dai = sc->sc_dai_codec;
- hwif = dai->dd_hw_if;
- if (hwif->trigger_input) {
- error = hwif->trigger_input(dai->dd_cookie,
- start, end, blksize, intr, arg, param);
- if (error) {
- aplaudio_halt_input(cookie);
- return error;
+ for (i = 0; i < nitems(sc->sc_dai_codec); i++) {
+ dai = sc->sc_dai_codec[i];
+ if (dai == NULL)
+ continue;
+ hwif = dai->dd_hw_if;
+ if (hwif->trigger_input) {
+ error = hwif->trigger_input(dai->dd_cookie,
+ start, end, blksize, intr, arg, param);
+ if (error) {
+ aplaudio_halt_input(cookie);
+ return error;
+ }
}
}
struct aplaudio_softc *sc = cookie;
struct dai_device *dai;
const struct audio_hw_if *hwif;
+ int i;
- dai = sc->sc_dai_codec;
- hwif = dai->dd_hw_if;
- if (hwif->halt_output)
- hwif->halt_output(dai->dd_cookie);
+ for (i = 0; i < nitems(sc->sc_dai_codec); i++) {
+ dai = sc->sc_dai_codec[i];
+ if (dai == NULL)
+ continue;
+ hwif = dai->dd_hw_if;
+ if (hwif->halt_output)
+ hwif->halt_output(dai->dd_cookie);
+ }
dai = sc->sc_dai_cpu;
hwif = dai->dd_hw_if;
struct aplaudio_softc *sc = cookie;
struct dai_device *dai;
const struct audio_hw_if *hwif;
+ int i;
- dai = sc->sc_dai_codec;
- hwif = dai->dd_hw_if;
- if (hwif->halt_input)
- hwif->halt_input(dai->dd_cookie);
+ for (i = 0; i < nitems(sc->sc_dai_codec); i++) {
+ dai = sc->sc_dai_codec[i];
+ if (dai == NULL)
+ continue;
+ hwif = dai->dd_hw_if;
+ if (hwif->halt_input)
+ hwif->halt_input(dai->dd_cookie);
+ }
dai = sc->sc_dai_cpu;
hwif = dai->dd_hw_if;
-/* $OpenBSD: aplmca.c,v 1.2 2022/08/06 09:42:13 kettenis Exp $ */
+/* $OpenBSD: aplmca.c,v 1.3 2022/09/02 17:54:42 kettenis Exp $ */
/*
* Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
*
return 0;
}
+void
+aplmca_dai_link(struct aplmca_softc *sc, int master, int port)
+{
+ struct aplmca_dai *ad = &sc->sc_ad[master];
+
+ HWRITE4(sc, MCA_PORT_CLOCK_SEL(port),
+ (ad->ad_cluster + 1) << MCA_PORT_CLOCK_SEL_SHIFT);
+ HWRITE4(sc, MCA_PORT_DATA_SEL(port),
+ MCA_PORT_DATA_SEL_TXA(ad->ad_cluster));
+ HWRITE4(sc, MCA_PORT_ENABLE(port),
+ MCA_PORT_ENABLE_CLOCKS | MCA_PORT_ENABLE_TX_DATA);
+}
+
uint32_t *
aplmca_dai_next_dai(uint32_t *cells)
{
struct aplmca_softc *sc = aplmca_cd.cd_devs[0];
uint32_t *dais;
uint32_t *dai;
- uint32_t port;
+ uint32_t ports[2];
int nports = 0;
- int len;
+ int len, i;
len = OF_getproplen(node, "sound-dai");
if (len != 2 * sizeof(uint32_t) && len != 4 * sizeof(uint32_t))
dai = dais;
while (dai && dai < dais + (len / sizeof(uint32_t))) {
- if (dai[0] == sc->sc_phandle) {
- port = dai[1];
- nports++;
- break;
- }
+ if (dai[0] == sc->sc_phandle && nports < nitems(ports))
+ ports[nports++] = dai[1];
dai = aplmca_dai_next_dai(dai);
}
if (nports == 0)
return NULL;
+ for (i = 0; i < nports; i++) {
+ if (ports[i] >= sc->sc_nclusters)
+ return NULL;
+ }
- if (sc->sc_ad[port].ad_ac != NULL)
+ if (sc->sc_ad[ports[0]].ad_ac != NULL)
return NULL;
- if (aplmca_dai_init(sc, port))
+ /* Setup the primary cluster. */
+ if (aplmca_dai_init(sc, ports[0]))
return NULL;
- return &sc->sc_ad[port].ad_dai;
+ /*
+ * Additional interfaces receive the same output as the
+ * primary interface by linking the output port to the primary
+ * cluster.
+ */
+ for (i = 1; i < nports; i++)
+ aplmca_dai_link(sc, ports[0], ports[i]);
+
+ return &sc->sc_ad[ports[0]].ad_dai;
}
int