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