xref: /openbsd/sys/arch/arm64/dev/aplmca.c (revision 4bdff4be)
1 /*	$OpenBSD: aplmca.c,v 1.7 2023/07/26 11:09:24 kettenis Exp $	*/
2 /*
3  * Copyright (c) 2022 Mark Kettenis <kettenis@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/audioio.h>
21 #include <sys/device.h>
22 #include <sys/malloc.h>
23 #include <sys/fcntl.h>
24 
25 #include <machine/bus.h>
26 #include <machine/fdt.h>
27 
28 #include <dev/ofw/openfirm.h>
29 #include <dev/ofw/ofw_clock.h>
30 #include <dev/ofw/ofw_misc.h>
31 #include <dev/ofw/ofw_power.h>
32 #include <dev/ofw/fdt.h>
33 
34 #include <dev/audio_if.h>
35 
36 #include <arm64/dev/apldma.h>
37 
38 /*
39  * This driver is based on preliminary device tree bindings and will
40  * almost certainly need changes once the official bindings land in
41  * mainline Linux.  Support for these preliminary bindings will be
42  * dropped as soon as official bindings are available.
43  */
44 
45 #define MCA_CL_STRIDE		0x4000
46 #define MCA_SW_STRIDE		0x8000
47 #define MCA_SERDES_TXA		0x0300
48 
49 #define MCA_STATUS(idx)			((idx) * MCA_CL_STRIDE + 0x0000)
50 #define  MCA_STATUS_MCLK_EN		(1 << 0)
51 #define MCA_MCLK_CONF(idx)		((idx) * MCA_CL_STRIDE + 0x0004)
52 #define  MCA_MCLK_CONF_DIV_MASK		(0xf << 8)
53 #define  MCA_MCLK_CONF_DIV_SHIFT	8
54 
55 #define MCA_SYNCGEN_STATUS(idx)		((idx) * MCA_CL_STRIDE + 0x0100)
56 #define  MCA_SYNCGEN_STATUS_EN		(1 << 0)
57 #define MCA_SYNCGEN_MCLK_SEL(idx)	((idx) * MCA_CL_STRIDE + 0x0104)
58 #define MCA_SYNCGEN_HI_PERIOD(idx)	((idx) * MCA_CL_STRIDE + 0x0108)
59 #define MCA_SYNCGEN_LO_PERIOD(idx)	((idx) * MCA_CL_STRIDE + 0x010c)
60 
61 #define MCA_SERDES_BASE(idx, off)	((idx) * MCA_CL_STRIDE + (off))
62 #define MCA_SERDES_STATUS(idx, off)	(MCA_SERDES_BASE(idx, off) + 0x0000)
63 #define  MCA_SERDES_STATUS_EN		(1 << 0)
64 #define  MCA_SERDES_STATUS_RST		(1 << 1)
65 #define MCA_SERDES_CONF(idx, off)	(MCA_SERDES_BASE(idx, off) + 0x0004)
66 #define MCA_SERDES_CONF_NSLOTS_MASK	(0xf << 0)
67 #define MCA_SERDES_CONF_NSLOTS_SHIFT	0
68 #define MCA_SERDES_CONF_WIDTH_MASK	(0x1f << 4)
69 #define MCA_SERDES_CONF_WIDTH_32BIT	(0x10 << 4)
70 #define MCA_SERDES_CONF_BCLK_POL	(1 << 10)
71 #define MCA_SERDES_CONF_MAGIC		(0x7 << 12)
72 #define MCA_SERDES_CONF_SYNC_SEL_MASK	(0x7 << 16)
73 #define MCA_SERDES_CONF_SYNC_SEL_SHIFT	16
74 #define MCA_SERDES_BITSTART(idx, off)	(MCA_SERDES_BASE(idx, off) + 0x0008)
75 #define MCA_SERDES_CHANMASK0(idx, off)	(MCA_SERDES_BASE(idx, off) + 0x000c)
76 #define MCA_SERDES_CHANMASK1(idx, off)	(MCA_SERDES_BASE(idx, off) + 0x0010)
77 #define MCA_SERDES_CHANMASK2(idx, off)	(MCA_SERDES_BASE(idx, off) + 0x0014)
78 #define MCA_SERDES_CHANMASK3(idx, off)	(MCA_SERDES_BASE(idx, off) + 0x0018)
79 
80 #define MCA_PORT_ENABLE(idx)		((idx) * MCA_CL_STRIDE + 0x0600)
81 #define  MCA_PORT_ENABLE_CLOCKS		(0x3 << 1)
82 #define  MCA_PORT_ENABLE_TX_DATA	(1 << 3)
83 #define MCA_PORT_CLOCK_SEL(idx)		((idx) * MCA_CL_STRIDE + 0x0604)
84 #define  MCA_PORT_CLOCK_SEL_SHIFT	8
85 #define MCA_PORT_DATA_SEL(idx)		((idx) * MCA_CL_STRIDE + 0x0608)
86 #define  MCA_PORT_DATA_SEL_TXA(idx)	(1 << ((idx) * 2))
87 #define  MCA_PORT_DATA_SEL_TXB(idx)	(2 << ((idx) * 2))
88 
89 #define MCA_DMA_ADAPTER_A(idx)		((idx) * MCA_SW_STRIDE + 0x0000)
90 #define MCA_DMA_ADAPTER_B(idx)		((idx) * MCA_SW_STRIDE + 0x4000)
91 #define  MCA_DMA_ADAPTER_TX_LSB_PAD_SHIFT	0
92 #define  MCA_DMA_ADAPTER_TX_NCHANS_SHIFT	5
93 #define  MCA_DMA_ADAPTER_NCHANS_SHIFT		20
94 
95 
96 #define HREAD4(sc, reg)							\
97 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
98 #define HWRITE4(sc, reg, val)						\
99 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
100 #define HSET4(sc, reg, bits)						\
101 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
102 #define HCLR4(sc, reg, bits)						\
103 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
104 
105 struct aplmca_dai {
106 	struct aplmca_softc	*ad_sc;
107 	struct dai_device	ad_dai;
108 	int			ad_cluster;
109 
110 	struct apldma_channel	*ad_ac;
111 	void			*ad_pbuf;
112 };
113 
114 struct aplmca_softc {
115 	struct device		sc_dev;
116 	bus_space_tag_t		sc_iot;
117 	bus_space_handle_t	sc_ioh;
118 	bus_space_handle_t	sc_sw_ioh;
119 
120 	int			sc_node;
121 	uint32_t		sc_phandle;
122 
123 	int			sc_nclusters;
124 	struct aplmca_dai	*sc_ad;
125 };
126 
127 int	aplmca_set_format(void *, uint32_t, uint32_t, uint32_t);
128 int	aplmca_set_sysclk(void *, uint32_t);
129 
130 int	aplmca_open(void *, int);
131 int	aplmca_set_params(void *, int, int,
132 	    struct audio_params *, struct audio_params *);
133 void	*aplmca_allocm(void *, int, size_t, int, int);
134 void	aplmca_freem(void *, void *, int);
135 int	aplmca_trigger_output(void *, void *, void *, int,
136 	    void (*)(void *), void *, struct audio_params *);
137 int	aplmca_trigger_input(void *, void *, void *, int,
138 	    void (*)(void *), void *, struct audio_params *);
139 int	aplmca_halt_output(void *);
140 int	aplmca_halt_input(void *);
141 
142 const struct audio_hw_if aplmca_hw_if = {
143 	.open = aplmca_open,
144 	.set_params = aplmca_set_params,
145 	.allocm = aplmca_allocm,
146 	.freem = aplmca_freem,
147 	.trigger_output = aplmca_trigger_output,
148 	.trigger_input = aplmca_trigger_input,
149 	.halt_output = aplmca_halt_output,
150 	.halt_input = aplmca_halt_input,
151 };
152 
153 int	aplmca_match(struct device *, void *, void *);
154 void	aplmca_attach(struct device *, struct device *, void *);
155 int	aplmca_activate(struct device *, int);
156 
157 const struct cfattach aplmca_ca = {
158 	sizeof (struct aplmca_softc), aplmca_match, aplmca_attach, NULL,
159 	aplmca_activate
160 };
161 
162 struct cfdriver aplmca_cd = {
163 	NULL, "aplmca", DV_DULL
164 };
165 
166 int
167 aplmca_match(struct device *parent, void *match, void *aux)
168 {
169 	struct fdt_attach_args *faa = aux;
170 
171 	return OF_is_compatible(faa->fa_node, "apple,mca");
172 }
173 
174 void
175 aplmca_attach(struct device *parent, struct device *self, void *aux)
176 {
177 	struct aplmca_softc *sc = (struct aplmca_softc *)self;
178 	struct fdt_attach_args *faa = aux;
179 	int i;
180 
181 	if (faa->fa_nreg < 2) {
182 		printf(": no registers\n");
183 		return;
184 	}
185 
186 	sc->sc_iot = faa->fa_iot;
187 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
188 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
189 		printf(": can't map registers\n");
190 		return;
191 	}
192 	if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr,
193 	    faa->fa_reg[1].size, 0, &sc->sc_sw_ioh)) {
194 		bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
195 		printf(": can't map registers\n");
196 		return;
197 	}
198 
199 	sc->sc_node = faa->fa_node;
200 	sc->sc_phandle = OF_getpropint(faa->fa_node, "phandle", 0);
201 
202 	sc->sc_nclusters = OF_getpropint(faa->fa_node, "apple,nclusters", 6);
203 	sc->sc_ad = mallocarray(sc->sc_nclusters, sizeof(*sc->sc_ad),
204 	    M_DEVBUF, M_WAITOK | M_ZERO);
205 
206 	for (i = 0; i < sc->sc_nclusters; i++) {
207 		sc->sc_ad[i].ad_cluster = i;
208 		sc->sc_ad[i].ad_sc = sc;
209 		sc->sc_ad[i].ad_dai.dd_node = sc->sc_node;
210 		sc->sc_ad[i].ad_dai.dd_cookie = &sc->sc_ad[i];
211 		sc->sc_ad[i].ad_dai.dd_hw_if = &aplmca_hw_if;
212 		sc->sc_ad[i].ad_dai.dd_set_format = aplmca_set_format;
213 		sc->sc_ad[i].ad_dai.dd_set_sysclk = aplmca_set_sysclk;
214 	}
215 
216 	printf("\n");
217 
218 	power_domain_enable_idx(sc->sc_node, 0);
219 
220 	for (i = 0; i < sc->sc_nclusters; i++) {
221 		HCLR4(sc, MCA_SERDES_STATUS(i, MCA_SERDES_TXA),
222 		    MCA_SERDES_STATUS_EN);
223 		HCLR4(sc, MCA_SYNCGEN_STATUS(i), MCA_SYNCGEN_STATUS_EN);
224 		HCLR4(sc, MCA_STATUS(i), MCA_STATUS_MCLK_EN);
225 	}
226 }
227 
228 int
229 aplmca_activate(struct device *self, int act)
230 {
231 	struct aplmca_softc *sc = (struct aplmca_softc *)self;
232 	int i;
233 
234 	switch (act) {
235 	case DVACT_SUSPEND:
236 		for (i = 0; i < sc->sc_nclusters; i++) {
237 			if (sc->sc_ad[i].ad_ac)
238 				power_domain_disable_idx(sc->sc_node, i + 1);
239 		}
240 		power_domain_disable_idx(sc->sc_node, 0);
241 		break;
242 	case DVACT_RESUME:
243 		power_domain_enable_idx(sc->sc_node, 0);
244 		for (i = 0; i < sc->sc_nclusters; i++) {
245 			if (sc->sc_ad[i].ad_ac)
246 				power_domain_enable_idx(sc->sc_node, i + 1);
247 		}
248 		break;
249 	}
250 
251 	return 0;
252 }
253 
254 int
255 aplmca_dai_init(struct aplmca_softc *sc, int port)
256 {
257 	struct aplmca_dai *ad = &sc->sc_ad[port];
258 	uint32_t conf;
259 	char name[5];
260 	int idx;
261 
262 	/* Allocate DMA channel. */
263 	snprintf(name, sizeof(name), "tx%da", ad->ad_cluster);
264 	idx = OF_getindex(sc->sc_node, name, "dma-names");
265 	if (idx == -1)
266 		return ENOENT;
267 	ad->ad_ac = apldma_alloc_channel(idx);
268 	if (ad->ad_ac == NULL)
269 		return ENOENT;
270 
271 	power_domain_enable_idx(sc->sc_node, port + 1);
272 
273 	/* Basic SERDES configuration. */
274 	conf = HREAD4(sc, MCA_SERDES_CONF(ad->ad_cluster, MCA_SERDES_TXA));
275 	conf &= ~MCA_SERDES_CONF_SYNC_SEL_MASK;
276 	conf |= (ad->ad_cluster + 1) << MCA_SERDES_CONF_SYNC_SEL_SHIFT;
277 	conf |= MCA_SERDES_CONF_MAGIC;
278 	HWRITE4(sc, MCA_SERDES_CONF(ad->ad_cluster, MCA_SERDES_TXA), conf);
279 
280 	/* Output port configuration. */
281 	HWRITE4(sc, MCA_PORT_CLOCK_SEL(port),
282 	    (ad->ad_cluster + 1) << MCA_PORT_CLOCK_SEL_SHIFT);
283 	HWRITE4(sc, MCA_PORT_DATA_SEL(port),
284 	    MCA_PORT_DATA_SEL_TXA(ad->ad_cluster));
285 	HWRITE4(sc, MCA_PORT_ENABLE(port),
286 	    MCA_PORT_ENABLE_CLOCKS | MCA_PORT_ENABLE_TX_DATA);
287 
288 	return 0;
289 }
290 
291 void
292 aplmca_dai_link(struct aplmca_softc *sc, int master, int port)
293 {
294 	struct aplmca_dai *ad = &sc->sc_ad[master];
295 
296 	HWRITE4(sc, MCA_PORT_CLOCK_SEL(port),
297 	    (ad->ad_cluster + 1) << MCA_PORT_CLOCK_SEL_SHIFT);
298 	HWRITE4(sc, MCA_PORT_DATA_SEL(port),
299 	    MCA_PORT_DATA_SEL_TXA(ad->ad_cluster));
300 	HWRITE4(sc, MCA_PORT_ENABLE(port),
301 	    MCA_PORT_ENABLE_CLOCKS | MCA_PORT_ENABLE_TX_DATA);
302 }
303 
304 uint32_t *
305 aplmca_dai_next_dai(uint32_t *cells)
306 {
307 	uint32_t phandle = cells[0];
308 	int node, ncells;
309 
310 	node = OF_getnodebyphandle(phandle);
311 	if (node == 0)
312 		return NULL;
313 
314 	ncells = OF_getpropint(node, "#sound-dai-cells", 0);
315 	return cells + ncells + 1;
316 }
317 
318 struct dai_device *
319 aplmca_alloc_cluster(int node)
320 {
321 	struct aplmca_softc *sc = aplmca_cd.cd_devs[0];
322 	uint32_t *dais;
323 	uint32_t *dai;
324 	uint32_t ports[2];
325 	int nports = 0;
326 	int len, i;
327 
328 	len = OF_getproplen(node, "sound-dai");
329 	if (len != 2 * sizeof(uint32_t) && len != 4 * sizeof(uint32_t))
330 		return NULL;
331 
332 	dais = malloc(len, M_TEMP, M_WAITOK);
333 	OF_getpropintarray(node, "sound-dai", dais, len);
334 
335 	dai = dais;
336 	while (dai && dai < dais + (len / sizeof(uint32_t))) {
337 		if (dai[0] == sc->sc_phandle && nports < nitems(ports))
338 			ports[nports++] = dai[1];
339 		dai = aplmca_dai_next_dai(dai);
340 	}
341 
342 	free(dais, M_TEMP, len);
343 
344 	if (nports == 0)
345 		return NULL;
346 	for (i = 0; i < nports; i++) {
347 		if (ports[i] >= sc->sc_nclusters)
348 			return NULL;
349 	}
350 
351 	if (sc->sc_ad[ports[0]].ad_ac != NULL)
352 		return NULL;
353 
354 	/* Setup the primary cluster. */
355 	if (aplmca_dai_init(sc, ports[0]))
356 		return NULL;
357 
358 	/*
359 	 * Additional interfaces receive the same output as the
360 	 * primary interface by linking the output port to the primary
361 	 * cluster.
362 	 */
363 	for (i = 1; i < nports; i++)
364 		aplmca_dai_link(sc, ports[0], ports[i]);
365 
366 	return &sc->sc_ad[ports[0]].ad_dai;
367 }
368 
369 int
370 aplmca_set_format(void *cookie, uint32_t fmt, uint32_t pol,
371     uint32_t clk)
372 {
373 	struct aplmca_dai *ad = cookie;
374 	struct aplmca_softc *sc = ad->ad_sc;
375 	uint32_t conf;
376 
377 	conf = HREAD4(sc, MCA_SERDES_CONF(ad->ad_cluster, MCA_SERDES_TXA));
378 	conf &= ~MCA_SERDES_CONF_WIDTH_MASK;
379 	conf |= MCA_SERDES_CONF_WIDTH_32BIT;
380 
381 	switch (fmt) {
382 	case DAI_FORMAT_I2S:
383 		conf &= ~MCA_SERDES_CONF_BCLK_POL;
384 		break;
385 	case DAI_FORMAT_RJ:
386 	case DAI_FORMAT_LJ:
387 		conf |= MCA_SERDES_CONF_BCLK_POL;
388 		break;
389 	default:
390 		return EINVAL;
391 	}
392 
393 	if (pol & DAI_POLARITY_IB)
394 		conf ^= MCA_SERDES_CONF_BCLK_POL;
395 	if (pol & DAI_POLARITY_IF)
396 		return EINVAL;
397 
398 	if (!(clk & DAI_CLOCK_CBM) || !(clk & DAI_CLOCK_CFM))
399 		return EINVAL;
400 
401 	HWRITE4(sc, MCA_SERDES_CONF(ad->ad_cluster, MCA_SERDES_TXA), conf);
402 
403 	return 0;
404 }
405 
406 int
407 aplmca_set_sysclk(void *cookie, uint32_t rate)
408 {
409 	struct aplmca_dai *ad = cookie;
410 	struct aplmca_softc *sc = ad->ad_sc;
411 
412 	return clock_set_frequency_idx(sc->sc_node, ad->ad_cluster, rate);
413 }
414 
415 int
416 aplmca_open(void *cookie, int flags)
417 {
418 	if ((flags & (FWRITE | FREAD)) == (FWRITE | FREAD))
419 		return ENXIO;
420 
421 	return 0;
422 }
423 
424 int
425 aplmca_set_params(void *cookie, int setmode, int usemode,
426     struct audio_params *play, struct audio_params *rec)
427 {
428 	if (setmode & AUMODE_PLAY) {
429 		play->sample_rate = 48000;
430 		play->encoding = AUDIO_ENCODING_SLINEAR_LE;
431 		play->precision = 24;
432 		play->bps = 4;
433 		play->msb = 0;
434 		play->channels = 2;
435 	}
436 
437 	return 0;
438 }
439 
440 void *
441 aplmca_allocm(void *cookie, int direction, size_t size, int type,
442     int flags)
443 {
444 	struct aplmca_dai *ad = cookie;
445 
446 	if (direction == AUMODE_PLAY) {
447 		ad->ad_pbuf = apldma_allocm(ad->ad_ac, size, flags);
448 		return ad->ad_pbuf;
449 	}
450 
451 	return malloc(size, type, flags | M_ZERO);
452 }
453 
454 void
455 aplmca_freem(void *cookie, void *addr, int type)
456 {
457 	struct aplmca_dai *ad = cookie;
458 
459 	if (addr == ad->ad_pbuf) {
460 		apldma_freem(ad->ad_ac);
461 		return;
462 	}
463 
464 	free(addr, type, 0);
465 }
466 
467 int
468 aplmca_trigger_output(void *cookie, void *start, void *end, int blksize,
469     void (*intr)(void *), void *intrarg, struct audio_params *params)
470 {
471 	struct aplmca_dai *ad = cookie;
472 	struct aplmca_softc *sc = ad->ad_sc;
473 	uint32_t conf, period;
474 	int pad;
475 
476 	if (params->channels > 16)
477 		return EINVAL;
478 
479 	/* Finalize SERDES configuration. */
480 	conf = HREAD4(sc, MCA_SERDES_CONF(ad->ad_cluster, MCA_SERDES_TXA));
481 	conf &= ~MCA_SERDES_CONF_NSLOTS_MASK;
482 	conf |= ((params->channels - 1) << MCA_SERDES_CONF_NSLOTS_SHIFT);
483 	HWRITE4(sc, MCA_SERDES_CONF(ad->ad_cluster, MCA_SERDES_TXA), conf);
484 	HWRITE4(sc, MCA_SERDES_CHANMASK0(ad->ad_cluster, MCA_SERDES_TXA),
485 	    0xffffffff);
486 	HWRITE4(sc, MCA_SERDES_CHANMASK1(ad->ad_cluster, MCA_SERDES_TXA),
487 	    0xffffffff << params->channels);
488 	HWRITE4(sc, MCA_SERDES_CHANMASK2(ad->ad_cluster, MCA_SERDES_TXA),
489 	    0xffffffff);
490 	HWRITE4(sc, MCA_SERDES_CHANMASK3(ad->ad_cluster, MCA_SERDES_TXA),
491 	    0xffffffff << params->channels);
492 
493 	period = params->channels * 32;
494 	HWRITE4(sc, MCA_SYNCGEN_HI_PERIOD(ad->ad_cluster), period - 2);
495 	HWRITE4(sc, MCA_SYNCGEN_LO_PERIOD(ad->ad_cluster), 0);
496 	HWRITE4(sc, MCA_MCLK_CONF(ad->ad_cluster),
497 	    1 << MCA_MCLK_CONF_DIV_SHIFT);
498 
499 	clock_enable_idx(sc->sc_node, ad->ad_cluster);
500 
501 	HWRITE4(sc, MCA_SYNCGEN_MCLK_SEL(ad->ad_cluster),
502 	    ad->ad_cluster + 1);
503 
504 	HSET4(sc, MCA_STATUS(ad->ad_cluster), MCA_STATUS_MCLK_EN);
505 	HSET4(sc, MCA_SYNCGEN_STATUS(ad->ad_cluster),
506 	    MCA_SYNCGEN_STATUS_EN);
507 	HSET4(sc, MCA_SERDES_STATUS(ad->ad_cluster, MCA_SERDES_TXA),
508 	    MCA_SERDES_STATUS_EN);
509 
510 	pad = params->bps * 8 - params->precision;
511 	bus_space_write_4(sc->sc_iot, sc->sc_sw_ioh,
512 	    MCA_DMA_ADAPTER_A(ad->ad_cluster),
513 	    pad << MCA_DMA_ADAPTER_TX_LSB_PAD_SHIFT |
514 	    2 << MCA_DMA_ADAPTER_TX_NCHANS_SHIFT |
515 	    2 << MCA_DMA_ADAPTER_NCHANS_SHIFT);
516 
517 	return apldma_trigger_output(ad->ad_ac, start, end, blksize,
518 	    intr, intrarg, params);
519 }
520 
521 int
522 aplmca_trigger_input(void *cookie, void *start, void *end, int blksize,
523     void (*intr)(void *), void *intrarg, struct audio_params *params)
524 {
525 	printf("%s\n", __func__);
526 	return EIO;
527 }
528 
529 int
530 aplmca_halt_output(void *cookie)
531 {
532 	struct aplmca_dai *ad = cookie;
533 	struct aplmca_softc *sc = ad->ad_sc;
534 	int error;
535 
536 	error = apldma_halt_output(ad->ad_ac);
537 
538 	HCLR4(sc, MCA_SERDES_STATUS(ad->ad_cluster, MCA_SERDES_TXA),
539 	    MCA_SERDES_STATUS_EN);
540 	HCLR4(sc, MCA_SYNCGEN_STATUS(ad->ad_cluster),
541 	    MCA_SYNCGEN_STATUS_EN);
542 	HCLR4(sc, MCA_STATUS(ad->ad_cluster), MCA_STATUS_MCLK_EN);
543 
544 	clock_disable_idx(sc->sc_node, ad->ad_cluster);
545 
546 	return error;
547 }
548 
549 int
550 aplmca_halt_input(void *cookie)
551 {
552 	printf("%s\n", __func__);
553 	return 0;
554 }
555