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