xref: /openbsd-src/sys/dev/fdt/rkiis.c (revision 46035553bfdd96e63c94e32da0210227ec2e3cf1)
1 /* $OpenBSD: rkiis.c,v 1.1 2020/06/11 00:02:08 patrick Exp $ */
2 /* $NetBSD: rk_i2s.c,v 1.3 2020/02/29 05:51:10 isaki Exp $ */
3 /*-
4  * Copyright (c) 2019 Jared McNeill <jmcneill@invisible.ca>
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
21  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
23  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
24  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/device.h>
32 #include <sys/malloc.h>
33 
34 #include <machine/intr.h>
35 #include <machine/bus.h>
36 #include <machine/fdt.h>
37 
38 #include <dev/ofw/openfirm.h>
39 #include <dev/ofw/ofw_clock.h>
40 #include <dev/ofw/ofw_misc.h>
41 #include <dev/ofw/ofw_pinctrl.h>
42 #include <dev/ofw/fdt.h>
43 
44 #include <sys/audioio.h>
45 #include <dev/audio_if.h>
46 #include <dev/midi_if.h>
47 
48 #define	RK_I2S_FIFO_DEPTH	32
49 #define	RK_I2S_SAMPLE_RATE	48000
50 
51 #define	I2S_TXCR		0x00
52 #define	 TXCR_RCNT_MASK			(0x3f << 17)
53 #define	 TXCR_RCNT_SHIFT		17
54 #define	 TXCR_TCSR_MASK			(0x3 << 15)
55 #define	 TXCR_TCSR_SHIFT		15
56 #define	 TXCR_HWT			(1 << 14)
57 #define	 TXCR_SJM			(1 << 12)
58 #define	 TXCR_FBM			(1 << 11)
59 #define	 TXCR_IBM_MASK			(0x3 << 9)
60 #define	 TXCR_IBM_SHIFT			9
61 #define	 TXCR_PBM_MASK			(0x3 << 7)
62 #define	 TXCR_PBM_SHIFT			7
63 #define	 TXCR_TFS			(1 << 5)
64 #define	 TXCR_VDW_MASK			(0x1f << 0)
65 #define	 TXCR_VDW_SHIFT			0
66 #define	I2S_RXCR		0x04
67 #define	 RXCR_RCSR_MASK			(0x3 << 15)
68 #define	 RXCR_RCSR_SHIFT		15
69 #define	 RXCR_HWT			(1 << 14)
70 #define	 RXCR_SJM			(1 << 12)
71 #define	 RXCR_FBM			(1 << 11)
72 #define	 RXCR_IBM_MASK			(0x3 << 9)
73 #define	 RXCR_IBM_SHIFT			9
74 #define	 RXCR_PBM_MASK			(0x3 << 7)
75 #define	 RXCR_PBM_SHIFT			7
76 #define	 RXCR_TFS			(1 << 5)
77 #define	 RXCR_VDW_MASK			(0x1f << 0)
78 #define	 RXCR_VDW_SHIFT			0
79 #define	I2S_CKR			0x08
80 #define	 CKR_TRCM_MASK			(0x3 << 28)
81 #define	 CKR_TRCM_SHIFT			28
82 #define	 CKR_MSS			(1 << 27)
83 #define	 CKR_CKP			(1 << 26)
84 #define	 CKR_RLP			(1 << 25)
85 #define	 CKR_TLP			(1 << 24)
86 #define	 CKR_MDIV_MASK			(0xff << 16)
87 #define	 CKR_MDIV_SHIFT			16
88 #define	 CKR_RSD_MASK			(0xff << 8)
89 #define	 CKR_RSD_SHIFT			8
90 #define	 CKR_TSD_MASK			(0xff << 0)
91 #define	 CKR_TSD_SHIFT			0
92 #define	I2S_TXFIFOLR		0x0c
93 #define	 TXFIFOLR_TFL_MASK(n)		(0x3f << ((n) * 6))
94 #define	 TXFIFOLR_TFL_SHIFT(n)		((n) * 6)
95 #define	I2S_DMACR		0x10
96 #define	 DMACR_RDE			(1 << 24)
97 #define	 DMACR_RDL_MASK			(0x1f << 16)
98 #define	 DMACR_RDL_SHIFT		16
99 #define	 DMACR_TDE			(1 << 8)
100 #define	 DMACR_TDL_MASK			(0x1f << 0)
101 #define	 DMACR_TDL_SHIFT		0
102 #define	I2S_INTCR		0x14
103 #define	 INTCR_RFT_MASK			(0x1f << 20)
104 #define	 INTCR_RFT_SHIFT		20
105 #define	 INTCR_RXOIC			(1 << 18)
106 #define	 INTCR_RXOIE			(1 << 17)
107 #define	 INTCR_RXFIE			(1 << 16)
108 #define	 INTCR_TFT_MASK			(0x1f << 4)
109 #define	 INTCR_TFT_SHIFT		4
110 #define	 INTCR_TXUIC			(1 << 2)
111 #define	 INTCR_TXUIE			(1 << 1)
112 #define	 INTCR_TXEIE			(1 << 0)
113 #define	I2S_INTSR		0x18
114 #define	 INTSR_RXOI			(1 << 17)
115 #define	 INTSR_RXFI			(1 << 16)
116 #define	 INTSR_TXUI			(1 << 1)
117 #define	 INTSR_TXEI			(1 << 0)
118 #define	I2S_XFER		0x1c
119 #define	 XFER_RXS			(1 << 1)
120 #define	 XFER_TXS			(1 << 0)
121 #define	I2S_CLR			0x20
122 #define	 CLR_RXC			(1 << 1)
123 #define	 CLR_TXC			(1 << 0)
124 #define	I2S_TXDR		0x24
125 #define	I2S_RXDR		0x28
126 #define	I2S_RXFIFOLR		0x2c
127 #define	 RXFIFOLR_RFL_MASK(n)		(0x3f << ((n) * 6))
128 #define	 RXFIFOLR_RFL_SHIFT(n)		((n) * 6)
129 
130 #define HREAD4(sc, reg)							\
131 	(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
132 #define HWRITE4(sc, reg, val)						\
133 	bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val))
134 #define HSET4(sc, reg, bits)						\
135 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits))
136 #define HCLR4(sc, reg, bits)						\
137 	HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits))
138 
139 int rkiis_match(struct device *, void *, void *);
140 void rkiis_attach(struct device *, struct device *, void *);
141 
142 int rkiis_intr(void *);
143 int rkiis_set_format(void *, uint32_t, uint32_t, uint32_t);
144 int rkiis_set_sysclk(void *, uint32_t);
145 
146 int rkiis_open(void *, int);
147 void rkiis_close(void *);
148 int rkiis_set_params(void *, int, int,
149     struct audio_params *, struct audio_params *);
150 void *rkiis_allocm(void *, int, size_t, int, int);
151 void rkiis_freem(void *, void *, int);
152 int rkiis_get_props(void *);
153 int rkiis_trigger_output(void *, void *, void *, int,
154     void (*)(void *), void *, struct audio_params *);
155 int rkiis_trigger_input(void *, void *, void *, int,
156     void (*)(void *), void *, struct audio_params *);
157 int rkiis_halt_output(void *);
158 int rkiis_halt_input(void *);
159 
160 struct rkiis_config {
161 	bus_size_t		oe_reg;
162 	uint32_t		oe_mask;
163 	uint32_t		oe_shift;
164 	uint32_t		oe_val;
165 };
166 
167 struct rkiis_config rk3399_i2s_config = {
168 	.oe_reg = 0xe220,
169 	.oe_mask = 0x7,
170 	.oe_shift = 11,
171 	.oe_val = 0x7,
172 };
173 
174 struct rkiis_chan {
175 	uint32_t		*ch_start;
176 	uint32_t		*ch_end;
177 	uint32_t		*ch_cur;
178 
179 	int			ch_blksize;
180 	int			ch_resid;
181 
182 	void			(*ch_intr)(void *);
183 	void			*ch_intrarg;
184 };
185 
186 struct rkiis_softc {
187 	struct device		sc_dev;
188 	bus_space_tag_t		sc_iot;
189 	bus_space_handle_t	sc_ioh;
190 	void			*sc_ih;
191 
192 	int			sc_node;
193 	struct rkiis_config	*sc_conf;
194 
195 	struct rkiis_chan	sc_pchan;
196 	struct rkiis_chan	sc_rchan;
197 
198 	uint32_t		sc_active;
199 
200 	struct dai_device	sc_dai;
201 };
202 
203 struct audio_hw_if rkiis_hw_if = {
204 	.set_params = rkiis_set_params,
205 	.get_props = rkiis_get_props,
206 	.allocm = rkiis_allocm,
207 	.freem = rkiis_freem,
208 	.trigger_output = rkiis_trigger_output,
209 	.trigger_input = rkiis_trigger_input,
210 	.halt_output = rkiis_halt_output,
211 	.halt_input = rkiis_halt_input,
212 };
213 
214 struct cfattach rkiis_ca = {
215 	sizeof (struct rkiis_softc), rkiis_match, rkiis_attach
216 };
217 
218 struct cfdriver rkiis_cd = {
219 	NULL, "rkiis", DV_DULL
220 };
221 
222 int
223 rkiis_match(struct device *parent, void *match, void *aux)
224 {
225 	struct fdt_attach_args *faa = aux;
226 
227 	return OF_is_compatible(faa->fa_node, "rockchip,rk3399-i2s");
228 }
229 
230 void
231 rkiis_attach(struct device *parent, struct device *self, void *aux)
232 {
233 	struct rkiis_softc *sc = (struct rkiis_softc *)self;
234 	struct fdt_attach_args *faa = aux;
235 	struct regmap *rm;
236 	uint32_t grf, val;
237 
238 	if (faa->fa_nreg < 1) {
239 		printf(": no registers\n");
240 		return;
241 	}
242 
243 	sc->sc_iot = faa->fa_iot;
244 	sc->sc_node = faa->fa_node;
245 	sc->sc_conf = &rk3399_i2s_config;
246 
247 	if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
248 	    faa->fa_reg[0].size, 0, &sc->sc_ioh)) {
249 		printf(": can't map registers\n");
250 		return;
251 	}
252 
253 	pinctrl_byname(sc->sc_node, "default");
254 	clock_enable_all(sc->sc_node);
255 
256 	grf = OF_getpropint(sc->sc_node, "rockchip,grf", 0);
257 	rm = regmap_byphandle(grf);
258 	if (rm && sc->sc_conf->oe_mask) {
259 		val = sc->sc_conf->oe_val << sc->sc_conf->oe_shift;
260 		val |= (sc->sc_conf->oe_mask << sc->sc_conf->oe_shift) << 16;
261 		regmap_write_4(rm, sc->sc_conf->oe_reg, val);
262 	}
263 
264 	sc->sc_ih = fdt_intr_establish(faa->fa_node, IPL_AUDIO | IPL_MPSAFE,
265 	    rkiis_intr, sc, sc->sc_dev.dv_xname);
266 	if (sc->sc_ih == NULL) {
267 		printf(": can't establish interrupt\n");
268 		goto unmap;
269 	}
270 
271 	printf("\n");
272 
273 	sc->sc_dai.dd_node = faa->fa_node;
274 	sc->sc_dai.dd_cookie = sc;
275 	sc->sc_dai.dd_hw_if = &rkiis_hw_if;
276 	sc->sc_dai.dd_set_format = rkiis_set_format;
277 	sc->sc_dai.dd_set_sysclk = rkiis_set_sysclk;
278 	dai_register(&sc->sc_dai);
279 	return;
280 
281 unmap:
282 	bus_space_unmap(sc->sc_iot, sc->sc_ioh, faa->fa_reg[0].size);
283 }
284 
285 int
286 rkiis_intr(void *cookie)
287 {
288 	struct rkiis_softc *sc = cookie;
289 	struct rkiis_chan *pch = &sc->sc_pchan;
290 #if notyet
291 	struct rkiis_chan *rch = &sc->sc_rchan;
292 #endif
293 	uint32_t sr, val;
294 	int fifolr;
295 
296 	mtx_enter(&audio_lock);
297 
298 	sr = HREAD4(sc, I2S_INTSR);
299 
300 	if ((sr & INTSR_RXFI) != 0) {
301 #if notyet
302 		val = HREAD4(sc, I2S_RXFIFOLR);
303 		fifolr = val & RXFIFOLR_RFL_MASK(0);
304 		fifolr >>= RXFIFOLR_RFL_SHIFT(0);
305 		while (fifolr > 0) {
306 			*rch->ch_data = HREAD4(sc, I2S_RXDR);
307 			rch->ch_data++;
308 			rch->ch_resid -= 4;
309 			if (rch->ch_resid == 0)
310 				rch->ch_intr(rch->ch_intrarg);
311 			--fifolr;
312 		}
313 #endif
314 	}
315 
316 	if ((sr & INTSR_TXEI) != 0) {
317 		val = HREAD4(sc, I2S_TXFIFOLR);
318 		fifolr = val & TXFIFOLR_TFL_MASK(0);
319 		fifolr >>= TXFIFOLR_TFL_SHIFT(0);
320 		fifolr = min(fifolr, RK_I2S_FIFO_DEPTH);
321 		while (fifolr < RK_I2S_FIFO_DEPTH - 1) {
322 			HWRITE4(sc, I2S_TXDR, *pch->ch_cur);
323 			pch->ch_cur++;
324 			if (pch->ch_cur == pch->ch_end)
325 				pch->ch_cur = pch->ch_start;
326 			pch->ch_resid -= 4;
327 			if (pch->ch_resid == 0) {
328 				pch->ch_intr(pch->ch_intrarg);
329 				pch->ch_resid = pch->ch_blksize;
330 			}
331 			++fifolr;
332 		}
333 	}
334 
335 	mtx_leave(&audio_lock);
336 
337 	return 1;
338 }
339 
340 int
341 rkiis_set_format(void *cookie, uint32_t fmt, uint32_t pol,
342     uint32_t clk)
343 {
344 	struct rkiis_softc *sc = cookie;
345 	uint32_t txcr, rxcr, ckr;
346 
347 	txcr = HREAD4(sc, I2S_TXCR);
348 	rxcr = HREAD4(sc, I2S_RXCR);
349 	ckr = HREAD4(sc, I2S_CKR);
350 
351 	txcr &= ~(TXCR_IBM_MASK|TXCR_PBM_MASK|TXCR_TFS);
352 	rxcr &= ~(RXCR_IBM_MASK|RXCR_PBM_MASK|RXCR_TFS);
353 	switch (fmt) {
354 	case DAI_FORMAT_I2S:
355 		txcr |= 0 << TXCR_IBM_SHIFT;
356 		rxcr |= 0 << RXCR_IBM_SHIFT;
357 		break;
358 	case DAI_FORMAT_LJ:
359 		txcr |= 1 << TXCR_IBM_SHIFT;
360 		rxcr |= 1 << RXCR_IBM_SHIFT;
361 		break;
362 	case DAI_FORMAT_RJ:
363 		txcr |= 2 << TXCR_IBM_SHIFT;
364 		rxcr |= 2 << RXCR_IBM_SHIFT;
365 		break;
366 	case DAI_FORMAT_DSPA:
367 		txcr |= 0 << TXCR_PBM_SHIFT;
368 		txcr |= TXCR_TFS;
369 		rxcr |= 0 << RXCR_PBM_SHIFT;
370 		txcr |= RXCR_TFS;
371 		break;
372 	case DAI_FORMAT_DSPB:
373 		txcr |= 1 << TXCR_PBM_SHIFT;
374 		txcr |= TXCR_TFS;
375 		rxcr |= 1 << RXCR_PBM_SHIFT;
376 		txcr |= RXCR_TFS;
377 		break;
378 	default:
379 		return EINVAL;
380 	}
381 
382 	HWRITE4(sc, I2S_TXCR, txcr);
383 	HWRITE4(sc, I2S_RXCR, rxcr);
384 
385 	switch (pol) {
386 	case DAI_POLARITY_IB|DAI_POLARITY_NF:
387 		ckr |= CKR_CKP;
388 		break;
389 	case DAI_POLARITY_NB|DAI_POLARITY_NF:
390 		ckr &= ~CKR_CKP;
391 		break;
392 	default:
393 		return EINVAL;
394 	}
395 
396 	switch (clk) {
397 	case DAI_CLOCK_CBM|DAI_CLOCK_CFM:
398 		ckr |= CKR_MSS;		/* sclk input */
399 		break;
400 	case DAI_CLOCK_CBS|DAI_CLOCK_CFS:
401 		ckr &= ~CKR_MSS;	/* sclk output */
402 		break;
403 	default:
404 		return EINVAL;
405 	}
406 
407 	HWRITE4(sc, I2S_CKR, ckr);
408 
409 	return 0;
410 }
411 
412 int
413 rkiis_set_sysclk(void *cookie, uint32_t rate)
414 {
415 	struct rkiis_softc *sc = cookie;
416 	int error;
417 
418 	error = clock_set_frequency(sc->sc_node, "i2s_clk", rate);
419 	if (error != 0) {
420 		printf("%s: can't set sysclk to %u Hz\n",
421 		    sc->sc_dev.dv_xname, rate);
422 		return error;
423 	}
424 
425 	return 0;
426 }
427 
428 int
429 rkiis_set_params(void *cookie, int setmode, int usemode,
430     struct audio_params *play, struct audio_params *rec)
431 {
432 	struct rkiis_softc *sc = cookie;
433 	uint32_t mclk_rate, bclk_rate;
434 	uint32_t bclk_div, lrck_div;
435 	uint32_t ckr, txcr, rxcr;
436 	int i;
437 
438 	ckr = HREAD4(sc, I2S_CKR);
439 	if ((ckr & CKR_MSS) == 0) {
440 		mclk_rate = clock_get_frequency(sc->sc_node, "i2s_clk");
441 		bclk_rate = 2 * 32 * RK_I2S_SAMPLE_RATE;
442 		bclk_div = mclk_rate / bclk_rate;
443 		lrck_div = bclk_rate / RK_I2S_SAMPLE_RATE;
444 
445 		ckr &= ~CKR_MDIV_MASK;
446 		ckr |= (bclk_div - 1) << CKR_MDIV_SHIFT;
447 		ckr &= ~CKR_TSD_MASK;
448 		ckr |= (lrck_div - 1) << CKR_TSD_SHIFT;
449 		ckr &= ~CKR_RSD_MASK;
450 		ckr |= (lrck_div - 1) << CKR_RSD_SHIFT;
451 	}
452 
453 	ckr &= ~CKR_TRCM_MASK;
454 	HWRITE4(sc, I2S_CKR, ckr);
455 
456 	for (i = 0; i < 2; i++) {
457 		struct audio_params *p;
458 		int mode;
459 
460 		switch (i) {
461 		case 0:
462 			mode = AUMODE_PLAY;
463 			p = play;
464 			break;
465 		case 1:
466 			mode = AUMODE_RECORD;
467 			p = rec;
468 			break;
469 		default:
470 			return EINVAL;
471 		}
472 
473 		if (!(setmode & mode))
474 			continue;
475 
476 		if (p->channels & 1)
477 			return EINVAL;
478 
479 		if (setmode & AUMODE_PLAY) {
480 			txcr = HREAD4(sc, I2S_TXCR);
481 			txcr &= ~TXCR_VDW_MASK;
482 			txcr |= (16 - 1) << TXCR_VDW_SHIFT;
483 			txcr &= ~TXCR_TCSR_MASK;
484 			txcr |= (p->channels / 2 - 1) << TXCR_TCSR_SHIFT;
485 			HWRITE4(sc, I2S_TXCR, txcr);
486 		} else {
487 			rxcr = HREAD4(sc, I2S_RXCR);
488 			rxcr &= ~RXCR_VDW_MASK;
489 			rxcr |= (16 - 1) << RXCR_VDW_SHIFT;
490 			rxcr &= ~RXCR_RCSR_MASK;
491 			rxcr |= (p->channels / 2 - 1) << RXCR_RCSR_SHIFT;
492 			HWRITE4(sc, I2S_RXCR, rxcr);
493 		}
494 
495 		p->encoding = AUDIO_ENCODING_SLINEAR_LE;
496 		p->precision = 16;
497 		p->bps = AUDIO_BPS(p->precision);
498 		p->msb = 1;
499 		p->sample_rate = RK_I2S_SAMPLE_RATE;
500 	}
501 
502 	return 0;
503 }
504 
505 int
506 rkiis_get_props(void *cookie)
507 {
508 	return 0;
509 }
510 
511 void *
512 rkiis_allocm(void *cookie, int direction, size_t size, int type,
513     int flags)
514 {
515 	return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO);
516 }
517 
518 void
519 rkiis_freem(void *cookie, void *addr, int size)
520 {
521 	free(addr, M_DEVBUF, size);
522 }
523 
524 int
525 rkiis_trigger_output(void *cookie, void *start, void *end, int blksize,
526     void (*intr)(void *), void *intrarg, struct audio_params *params)
527 {
528 	struct rkiis_softc *sc = cookie;
529 	struct rkiis_chan *ch = &sc->sc_pchan;
530 	uint32_t val;
531 
532 	if (sc->sc_active == 0) {
533 		val = HREAD4(sc, I2S_XFER);
534 		val |= (XFER_TXS | XFER_RXS);
535 		HWRITE4(sc, I2S_XFER, val);
536 	}
537 
538 	sc->sc_active |= XFER_TXS;
539 
540 	val = HREAD4(sc, I2S_INTCR);
541 	val |= INTCR_TXEIE;
542 	val &= ~INTCR_TFT_MASK;
543 	val |= (RK_I2S_FIFO_DEPTH / 2) << INTCR_TFT_SHIFT;
544 	HWRITE4(sc, I2S_INTCR, val);
545 
546 	ch->ch_intr = intr;
547 	ch->ch_intrarg = intrarg;
548 	ch->ch_start = ch->ch_cur = start;
549 	ch->ch_end = end;
550 	ch->ch_blksize = blksize;
551 	ch->ch_resid = blksize;
552 
553 	return 0;
554 }
555 
556 int
557 rkiis_trigger_input(void *cookie, void *start, void *end, int blksize,
558     void (*intr)(void *), void *intrarg, struct audio_params *params)
559 {
560 	return EIO;
561 }
562 
563 int
564 rkiis_halt_output(void *cookie)
565 {
566 	struct rkiis_softc *sc = cookie;
567 	struct rkiis_chan *ch = &sc->sc_pchan;
568 	uint32_t val;
569 
570 	sc->sc_active &= ~XFER_TXS;
571 	if (sc->sc_active == 0) {
572 		val = HREAD4(sc, I2S_XFER);
573 		val &= ~(XFER_TXS|XFER_RXS);
574 		HWRITE4(sc, I2S_XFER, val);
575 	}
576 
577 	val = HREAD4(sc, I2S_INTCR);
578 	val &= ~INTCR_TXEIE;
579 	HWRITE4(sc, I2S_INTCR, val);
580 
581 	val = HREAD4(sc, I2S_CLR);
582 	val |= CLR_TXC;
583 	HWRITE4(sc, I2S_CLR, val);
584 
585 	while ((HREAD4(sc, I2S_CLR) & CLR_TXC) != 0)
586 		delay(1);
587 
588 	ch->ch_intr = NULL;
589 	ch->ch_intrarg = NULL;
590 
591 	return 0;
592 }
593 
594 int
595 rkiis_halt_input(void *cookie)
596 {
597 	struct rkiis_softc *sc = cookie;
598 	struct rkiis_chan *ch = &sc->sc_rchan;
599 	uint32_t val;
600 
601 	sc->sc_active &= ~XFER_RXS;
602 	if (sc->sc_active == 0) {
603 		val = HREAD4(sc, I2S_XFER);
604 		val &= ~(XFER_TXS|XFER_RXS);
605 		HWRITE4(sc, I2S_XFER, val);
606 	}
607 
608 	val = HREAD4(sc, I2S_INTCR);
609 	val &= ~INTCR_RXFIE;
610 	HWRITE4(sc, I2S_INTCR, val);
611 
612 	ch->ch_intr = NULL;
613 	ch->ch_intrarg = NULL;
614 
615 	return 0;
616 }
617