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