1 /* $NetBSD: rk_i2s.c,v 1.3 2020/02/29 05:51:10 isaki Exp $ */ 2 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/cdefs.h> 30 __KERNEL_RCSID(0, "$NetBSD: rk_i2s.c,v 1.3 2020/02/29 05:51:10 isaki Exp $"); 31 32 #include <sys/param.h> 33 #include <sys/bus.h> 34 #include <sys/cpu.h> 35 #include <sys/device.h> 36 #include <sys/kmem.h> 37 38 #include <sys/audioio.h> 39 #include <dev/audio/audio_if.h> 40 #include <dev/audio/linear.h> 41 42 #include <dev/fdt/fdtvar.h> 43 #include <dev/fdt/syscon.h> 44 45 #define RK_I2S_FIFO_DEPTH 32 46 #define RK_I2S_SAMPLE_RATE 48000 47 48 #define I2S_TXCR 0x00 49 #define TXCR_RCNT __BITS(22,17) 50 #define TXCR_TCSR __BITS(16,15) 51 #define TXCR_HWT __BIT(14) 52 #define TXCR_SJM __BIT(12) 53 #define TXCR_FBM __BIT(11) 54 #define TXCR_IBM __BITS(10,9) 55 #define TXCR_PBM __BITS(8,7) 56 #define TXCR_TFS __BIT(5) 57 #define TXCR_VDW __BITS(4,0) 58 #define I2S_RXCR 0x04 59 #define RXCR_RCSR __BITS(16,15) 60 #define RXCR_HWT __BIT(14) 61 #define RXCR_SJM __BIT(12) 62 #define RXCR_FBM __BIT(11) 63 #define RXCR_IBM __BITS(10,9) 64 #define RXCR_PBM __BITS(8,7) 65 #define RXCR_TFS __BIT(5) 66 #define RXCR_VDW __BITS(4,0) 67 #define I2S_CKR 0x08 68 #define CKR_TRCM __BITS(29,28) 69 #define CKR_MSS __BIT(27) 70 #define CKR_CKP __BIT(26) 71 #define CKR_RLP __BIT(25) 72 #define CKR_TLP __BIT(24) 73 #define CKR_MDIV __BITS(23,16) 74 #define CKR_RSD __BITS(15,8) 75 #define CKR_TSD __BITS(7,0) 76 #define I2S_TXFIFOLR 0x0c 77 #define TXFIFOLR_TFL(n) __BITS((n) * 6 + 5, (n) * 6) 78 #define I2S_DMACR 0x10 79 #define DMACR_RDE __BIT(24) 80 #define DMACR_RDL __BITS(20,16) 81 #define DMACR_TDE __BIT(8) 82 #define DMACR_TDL __BITS(4,0) 83 #define I2S_INTCR 0x14 84 #define INTCR_RFT __BITS(24,20) 85 #define INTCR_RXOIC __BIT(18) 86 #define INTCR_RXOIE __BIT(17) 87 #define INTCR_RXFIE __BIT(16) 88 #define INTCR_TFT __BITS(8,4) 89 #define INTCR_TXUIC __BIT(2) 90 #define INTCR_TXUIE __BIT(1) 91 #define INTCR_TXEIE __BIT(0) 92 #define I2S_INTSR 0x18 93 #define INTSR_RXOI __BIT(17) 94 #define INTSR_RXFI __BIT(16) 95 #define INTSR_TXUI __BIT(1) 96 #define INTSR_TXEI __BIT(0) 97 #define I2S_XFER 0x1c 98 #define XFER_RXS __BIT(1) 99 #define XFER_TXS __BIT(0) 100 #define I2S_CLR 0x20 101 #define CLR_RXC __BIT(1) 102 #define CLR_TXC __BIT(0) 103 #define I2S_TXDR 0x24 104 #define I2S_RXDR 0x28 105 #define I2S_RXFIFOLR 0x2c 106 #define RXFIFOLR_RFL(n) __BITS((n) * 6 + 5, (n) * 6) 107 108 struct rk_i2s_config { 109 bus_size_t oe_reg; 110 u_int oe_mask; 111 u_int oe_val; 112 }; 113 114 static const struct rk_i2s_config rk3399_i2s_config = { 115 .oe_reg = 0x0e220, 116 .oe_mask = __BITS(13,11), 117 .oe_val = 0x7, 118 }; 119 120 static const struct of_compat_data compat_data[] = { 121 { "rockchip,rk3399-i2s", (uintptr_t)&rk3399_i2s_config }, 122 { NULL } 123 }; 124 125 struct rk_i2s_softc; 126 127 struct rk_i2s_chan { 128 uint32_t *ch_start; 129 uint32_t *ch_end; 130 uint32_t *ch_cur; 131 132 int ch_blksize; 133 int ch_resid; 134 135 void (*ch_intr)(void *); 136 void *ch_intrarg; 137 }; 138 139 struct rk_i2s_softc { 140 device_t sc_dev; 141 bus_space_tag_t sc_bst; 142 bus_space_handle_t sc_bsh; 143 int sc_phandle; 144 struct clk *sc_clk; 145 struct syscon *sc_grf; 146 const struct rk_i2s_config *sc_conf; 147 148 kmutex_t sc_lock; 149 kmutex_t sc_intr_lock; 150 151 struct audio_format sc_format; 152 153 struct rk_i2s_chan sc_pchan; 154 struct rk_i2s_chan sc_rchan; 155 156 u_int sc_active; 157 158 struct audio_dai_device sc_dai; 159 }; 160 161 #define RD4(sc, reg) \ 162 bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) 163 #define WR4(sc, reg, val) \ 164 bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) 165 166 static int 167 rk_i2s_query_format(void *priv, audio_format_query_t *afp) 168 { 169 struct rk_i2s_softc * const sc = priv; 170 171 return audio_query_format(&sc->sc_format, 1, afp); 172 } 173 174 static int 175 rk_i2s_set_format(void *priv, int setmode, 176 const audio_params_t *play, const audio_params_t *rec, 177 audio_filter_reg_t *pfil, audio_filter_reg_t *rfil) 178 { 179 struct rk_i2s_softc * const sc = priv; 180 uint32_t ckr, txcr, rxcr; 181 182 ckr = RD4(sc, I2S_CKR); 183 if ((ckr & CKR_MSS) == 0) { 184 const u_int mclk_rate = clk_get_rate(sc->sc_clk); 185 const u_int bclk_rate = 2 * 32 * RK_I2S_SAMPLE_RATE; 186 const u_int bclk_div = mclk_rate / bclk_rate; 187 const u_int lrck_div = bclk_rate / RK_I2S_SAMPLE_RATE; 188 189 ckr &= ~CKR_MDIV; 190 ckr |= __SHIFTIN(bclk_div - 1, CKR_MDIV); 191 ckr &= ~CKR_TSD; 192 ckr |= __SHIFTIN(lrck_div - 1, CKR_TSD); 193 ckr &= ~CKR_RSD; 194 ckr |= __SHIFTIN(lrck_div - 1, CKR_RSD); 195 } 196 197 ckr &= ~CKR_TRCM; 198 ckr |= __SHIFTIN(0, CKR_TRCM); 199 WR4(sc, I2S_CKR, ckr); 200 201 if (play && (setmode & AUMODE_PLAY) != 0) { 202 if (play->channels & 1) 203 return EINVAL; 204 txcr = RD4(sc, I2S_TXCR); 205 txcr &= ~TXCR_VDW; 206 txcr |= __SHIFTIN(play->validbits - 1, TXCR_VDW); 207 txcr &= ~TXCR_TCSR; 208 txcr |= __SHIFTIN(play->channels / 2 - 1, TXCR_TCSR); 209 WR4(sc, I2S_TXCR, txcr); 210 } 211 212 if (rec && (setmode & AUMODE_RECORD) != 0) { 213 if (rec->channels & 1) 214 return EINVAL; 215 rxcr = RD4(sc, I2S_RXCR); 216 rxcr &= ~RXCR_VDW; 217 rxcr |= __SHIFTIN(rec->validbits - 1, RXCR_VDW); 218 rxcr &= ~RXCR_RCSR; 219 rxcr |= __SHIFTIN(rec->channels / 2 - 1, RXCR_RCSR); 220 WR4(sc, I2S_RXCR, rxcr); 221 } 222 223 return 0; 224 } 225 226 static int 227 rk_i2s_get_props(void *priv) 228 { 229 230 return AUDIO_PROP_PLAYBACK | AUDIO_PROP_CAPTURE | 231 AUDIO_PROP_FULLDUPLEX; 232 } 233 234 static void * 235 rk_i2s_allocm(void *priv, int dir, size_t size) 236 { 237 return kmem_zalloc(size, KM_SLEEP); 238 } 239 240 static void 241 rk_i2s_freem(void *priv, void *addr, size_t size) 242 { 243 kmem_free(addr, size); 244 } 245 246 static int 247 rk_i2s_trigger_output(void *priv, void *start, void *end, int blksize, 248 void (*intr)(void *), void *intrarg, const audio_params_t *params) 249 { 250 struct rk_i2s_softc * const sc = priv; 251 struct rk_i2s_chan *ch = &sc->sc_pchan; 252 uint32_t val; 253 254 if (sc->sc_active == 0) { 255 val = RD4(sc, I2S_XFER); 256 val |= (XFER_TXS | XFER_RXS); 257 WR4(sc, I2S_XFER, val); 258 } 259 260 sc->sc_active |= XFER_TXS; 261 262 val = RD4(sc, I2S_INTCR); 263 val |= INTCR_TXEIE; 264 val &= ~INTCR_TFT; 265 val |= __SHIFTIN(RK_I2S_FIFO_DEPTH / 2, INTCR_TFT); 266 WR4(sc, I2S_INTCR, val); 267 268 ch->ch_intr = intr; 269 ch->ch_intrarg = intrarg; 270 ch->ch_start = ch->ch_cur = start; 271 ch->ch_end = end; 272 ch->ch_blksize = blksize; 273 ch->ch_resid = blksize; 274 275 return 0; 276 } 277 278 static int 279 rk_i2s_trigger_input(void *priv, void *start, void *end, int blksize, 280 void (*intr)(void *), void *intrarg, const audio_params_t *params) 281 { 282 return EIO; 283 } 284 285 static int 286 rk_i2s_halt_output(void *priv) 287 { 288 struct rk_i2s_softc * const sc = priv; 289 struct rk_i2s_chan *ch = &sc->sc_pchan; 290 uint32_t val; 291 292 sc->sc_active &= ~XFER_TXS; 293 if (sc->sc_active == 0) { 294 val = RD4(sc, I2S_XFER); 295 val &= ~(XFER_TXS|XFER_RXS); 296 WR4(sc, I2S_XFER, val); 297 } 298 299 val = RD4(sc, I2S_INTCR); 300 val &= ~INTCR_TXEIE; 301 WR4(sc, I2S_INTCR, val); 302 303 val = RD4(sc, I2S_CLR); 304 val |= CLR_TXC; 305 WR4(sc, I2S_CLR, val); 306 307 while ((RD4(sc, I2S_CLR) & CLR_TXC) != 0) 308 delay(1); 309 310 ch->ch_intr = NULL; 311 ch->ch_intrarg = NULL; 312 313 return 0; 314 } 315 316 static int 317 rk_i2s_halt_input(void *priv) 318 { 319 struct rk_i2s_softc * const sc = priv; 320 struct rk_i2s_chan *ch = &sc->sc_rchan; 321 uint32_t val; 322 323 sc->sc_active &= ~XFER_RXS; 324 if (sc->sc_active == 0) { 325 val = RD4(sc, I2S_XFER); 326 val &= ~(XFER_TXS|XFER_RXS); 327 WR4(sc, I2S_XFER, val); 328 } 329 330 val = RD4(sc, I2S_INTCR); 331 val &= ~INTCR_RXFIE; 332 WR4(sc, I2S_INTCR, val); 333 334 ch->ch_intr = NULL; 335 ch->ch_intrarg = NULL; 336 337 return 0; 338 } 339 340 static void 341 rk_i2s_get_locks(void *priv, kmutex_t **intr, kmutex_t **thread) 342 { 343 struct rk_i2s_softc * const sc = priv; 344 345 *intr = &sc->sc_intr_lock; 346 *thread = &sc->sc_lock; 347 } 348 349 static const struct audio_hw_if rk_i2s_hw_if = { 350 .query_format = rk_i2s_query_format, 351 .set_format = rk_i2s_set_format, 352 .get_props = rk_i2s_get_props, 353 .allocm = rk_i2s_allocm, 354 .freem = rk_i2s_freem, 355 .trigger_output = rk_i2s_trigger_output, 356 .trigger_input = rk_i2s_trigger_input, 357 .halt_output = rk_i2s_halt_output, 358 .halt_input = rk_i2s_halt_input, 359 .get_locks = rk_i2s_get_locks, 360 }; 361 362 static int 363 rk_i2s_intr(void *priv) 364 { 365 struct rk_i2s_softc * const sc = priv; 366 struct rk_i2s_chan * const pch = &sc->sc_pchan; 367 #if notyet 368 struct rk_i2s_chan * const rch = &sc->sc_rchan; 369 #endif 370 uint32_t sr, val; 371 int fifolr; 372 373 mutex_enter(&sc->sc_intr_lock); 374 375 sr = RD4(sc, I2S_INTSR); 376 377 if ((sr & INTSR_RXFI) != 0) { 378 #if notyet 379 val = RD4(sc, I2S_RXFIFOLR); 380 fifolr = __SHIFTOUT(val, RXFIFOLR_RFL(0)); 381 while (fifolr > 0) { 382 *rch->ch_data = RD4(sc, I2S_RXDR); 383 rch->ch_data++; 384 rch->ch_resid -= 4; 385 if (rch->ch_resid == 0) 386 rch->ch_intr(rch->ch_intrarg); 387 --fifolr; 388 } 389 #endif 390 } 391 392 if ((sr & INTSR_TXEI) != 0) { 393 val = RD4(sc, I2S_TXFIFOLR); 394 fifolr = __SHIFTOUT(val, TXFIFOLR_TFL(0)); 395 fifolr = uimin(fifolr, RK_I2S_FIFO_DEPTH); 396 while (fifolr < RK_I2S_FIFO_DEPTH - 1) { 397 WR4(sc, I2S_TXDR, *pch->ch_cur); 398 pch->ch_cur++; 399 if (pch->ch_cur == pch->ch_end) 400 pch->ch_cur = pch->ch_start; 401 pch->ch_resid -= 4; 402 if (pch->ch_resid == 0) { 403 pch->ch_intr(pch->ch_intrarg); 404 pch->ch_resid = pch->ch_blksize; 405 } 406 ++fifolr; 407 } 408 } 409 410 mutex_exit(&sc->sc_intr_lock); 411 412 return 0; 413 } 414 415 static int 416 rk_i2s_dai_set_sysclk(audio_dai_tag_t dai, u_int rate, int dir) 417 { 418 struct rk_i2s_softc * const sc = audio_dai_private(dai); 419 int error; 420 421 error = clk_set_rate(sc->sc_clk, rate); 422 if (error != 0) { 423 device_printf(sc->sc_dev, "failed to set sysclk to %u Hz: %d\n", 424 rate, error); 425 return error; 426 } 427 428 return 0; 429 } 430 431 static int 432 rk_i2s_dai_set_format(audio_dai_tag_t dai, u_int format) 433 { 434 struct rk_i2s_softc * const sc = audio_dai_private(dai); 435 uint32_t txcr, rxcr, ckr; 436 437 const u_int fmt = __SHIFTOUT(format, AUDIO_DAI_FORMAT_MASK); 438 const u_int pol = __SHIFTOUT(format, AUDIO_DAI_POLARITY_MASK); 439 const u_int clk = __SHIFTOUT(format, AUDIO_DAI_CLOCK_MASK); 440 441 txcr = RD4(sc, I2S_TXCR); 442 rxcr = RD4(sc, I2S_RXCR); 443 ckr = RD4(sc, I2S_CKR); 444 445 txcr &= ~(TXCR_IBM|TXCR_PBM|TXCR_TFS); 446 rxcr &= ~(RXCR_IBM|RXCR_PBM|RXCR_TFS); 447 switch (fmt) { 448 case AUDIO_DAI_FORMAT_I2S: 449 txcr |= __SHIFTIN(0, TXCR_IBM); 450 rxcr |= __SHIFTIN(0, RXCR_IBM); 451 break; 452 case AUDIO_DAI_FORMAT_LJ: 453 txcr |= __SHIFTIN(1, TXCR_IBM); 454 rxcr |= __SHIFTIN(1, RXCR_IBM); 455 break; 456 case AUDIO_DAI_FORMAT_RJ: 457 txcr |= __SHIFTIN(2, TXCR_IBM); 458 rxcr |= __SHIFTIN(2, RXCR_IBM); 459 break; 460 case AUDIO_DAI_FORMAT_DSPA: 461 txcr |= __SHIFTIN(0, TXCR_PBM); 462 txcr |= TXCR_TFS; 463 rxcr |= __SHIFTIN(0, RXCR_PBM); 464 txcr |= RXCR_TFS; 465 break; 466 case AUDIO_DAI_FORMAT_DSPB: 467 txcr |= __SHIFTIN(1, TXCR_PBM); 468 txcr |= TXCR_TFS; 469 rxcr |= __SHIFTIN(1, RXCR_PBM); 470 txcr |= RXCR_TFS; 471 break; 472 default: 473 return EINVAL; 474 } 475 476 WR4(sc, I2S_TXCR, txcr); 477 WR4(sc, I2S_RXCR, rxcr); 478 479 switch (pol) { 480 case AUDIO_DAI_POLARITY_IB_NF: 481 ckr |= CKR_CKP; 482 break; 483 case AUDIO_DAI_POLARITY_NB_NF: 484 ckr &= ~CKR_CKP; 485 break; 486 default: 487 return EINVAL; 488 } 489 490 switch (clk) { 491 case AUDIO_DAI_CLOCK_CBM_CFM: 492 ckr |= CKR_MSS; /* sclk input */ 493 break; 494 case AUDIO_DAI_CLOCK_CBS_CFS: 495 ckr &= ~CKR_MSS; /* sclk output */ 496 break; 497 default: 498 return EINVAL; 499 } 500 501 WR4(sc, I2S_CKR, ckr); 502 503 return 0; 504 } 505 506 static audio_dai_tag_t 507 rk_i2s_dai_get_tag(device_t dev, const void *data, size_t len) 508 { 509 struct rk_i2s_softc * const sc = device_private(dev); 510 511 if (len != 4) 512 return NULL; 513 514 return &sc->sc_dai; 515 } 516 517 static struct fdtbus_dai_controller_func rk_i2s_dai_funcs = { 518 .get_tag = rk_i2s_dai_get_tag 519 }; 520 521 static int 522 rk_i2s_clock_init(struct rk_i2s_softc *sc) 523 { 524 const int phandle = sc->sc_phandle; 525 int error; 526 527 sc->sc_clk = fdtbus_clock_get(phandle, "i2s_clk"); 528 if (sc->sc_clk == NULL) { 529 aprint_error(": couldn't find i2s_clk clock\n"); 530 return ENXIO; 531 } 532 error = clk_enable(sc->sc_clk); 533 if (error != 0) { 534 aprint_error(": couldn't enable i2s_clk clock: %d\n", error); 535 return error; 536 } 537 538 /* Enable bus clock */ 539 if (fdtbus_clock_enable(phandle, "i2s_hclk", true) != 0) { 540 aprint_error(": couldn't enable i2s_hclk clock: %d\n", error); 541 return error; 542 } 543 544 return 0; 545 } 546 547 static int 548 rk_i2s_match(device_t parent, cfdata_t cf, void *aux) 549 { 550 struct fdt_attach_args * const faa = aux; 551 552 return of_match_compat_data(faa->faa_phandle, compat_data); 553 } 554 555 static void 556 rk_i2s_attach(device_t parent, device_t self, void *aux) 557 { 558 struct rk_i2s_softc * const sc = device_private(self); 559 struct fdt_attach_args * const faa = aux; 560 const int phandle = faa->faa_phandle; 561 char intrstr[128]; 562 bus_addr_t addr; 563 bus_size_t size; 564 uint32_t val; 565 566 if (fdtbus_get_reg(phandle, 0, &addr, &size) != 0) { 567 aprint_error(": couldn't get registers\n"); 568 return; 569 } 570 if (!fdtbus_intr_str(phandle, 0, intrstr, sizeof(intrstr))) { 571 aprint_error(": couldn't decode interrupt\n"); 572 return; 573 } 574 575 sc->sc_dev = self; 576 sc->sc_phandle = phandle; 577 sc->sc_bst = faa->faa_bst; 578 if (bus_space_map(sc->sc_bst, addr, size, 0, &sc->sc_bsh) != 0) { 579 aprint_error(": couldn't map registers\n"); 580 return; 581 } 582 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 583 mutex_init(&sc->sc_intr_lock, MUTEX_DEFAULT, IPL_SCHED); 584 585 sc->sc_conf = (void *)of_search_compatible(phandle, compat_data)->data; 586 sc->sc_grf = fdtbus_syscon_acquire(phandle, "rockchip,grf"); 587 if (sc->sc_grf != NULL && sc->sc_conf->oe_mask != 0) { 588 syscon_lock(sc->sc_grf); 589 val = __SHIFTIN(sc->sc_conf->oe_val, sc->sc_conf->oe_mask); 590 val |= (sc->sc_conf->oe_mask << 16); 591 syscon_write_4(sc->sc_grf, sc->sc_conf->oe_reg, val); 592 syscon_unlock(sc->sc_grf); 593 } 594 595 if (rk_i2s_clock_init(sc) != 0) 596 return; 597 598 aprint_naive("\n"); 599 aprint_normal(": I2S/PCM controller\n"); 600 601 if (fdtbus_intr_establish(phandle, 0, IPL_AUDIO, FDT_INTR_MPSAFE, rk_i2s_intr, sc) == NULL) { 602 aprint_error_dev(self, "couldn't establish interrupt on %s\n", intrstr); 603 return; 604 } 605 aprint_normal_dev(self, "interrupting on %s\n", intrstr); 606 607 sc->sc_format.mode = AUMODE_PLAY|AUMODE_RECORD; 608 sc->sc_format.encoding = AUDIO_ENCODING_SLINEAR_LE; 609 sc->sc_format.validbits = 16; 610 sc->sc_format.precision = 16; 611 sc->sc_format.channels = 2; 612 sc->sc_format.channel_mask = AUFMT_STEREO; 613 sc->sc_format.frequency_type = 1; 614 sc->sc_format.frequency[0] = RK_I2S_SAMPLE_RATE; 615 616 sc->sc_dai.dai_set_sysclk = rk_i2s_dai_set_sysclk; 617 sc->sc_dai.dai_set_format = rk_i2s_dai_set_format; 618 sc->sc_dai.dai_hw_if = &rk_i2s_hw_if; 619 sc->sc_dai.dai_dev = self; 620 sc->sc_dai.dai_priv = sc; 621 fdtbus_register_dai_controller(self, phandle, &rk_i2s_dai_funcs); 622 } 623 624 CFATTACH_DECL_NEW(rk_i2s, sizeof(struct rk_i2s_softc), 625 rk_i2s_match, rk_i2s_attach, NULL, NULL); 626