1 1.1 nisimura /*- 2 1.1 nisimura * Copyright (c) 2012 The NetBSD Foundation, Inc. 3 1.1 nisimura * All rights reserved. 4 1.1 nisimura * 5 1.1 nisimura * This code is derived from software contributed to The NetBSD Foundation 6 1.1 nisimura * by Paul Fleischer <paul (at) xpg.dk> 7 1.1 nisimura * 8 1.1 nisimura * Redistribution and use in source and binary forms, with or without 9 1.1 nisimura * modification, are permitted provided that the following conditions 10 1.1 nisimura * are met: 11 1.1 nisimura * 1. Redistributions of source code must retain the above copyright 12 1.1 nisimura * notice, this list of conditions and the following disclaimer. 13 1.1 nisimura * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 nisimura * notice, this list of conditions and the following disclaimer in the 15 1.1 nisimura * documentation and/or other materials provided with the distribution. 16 1.1 nisimura * 17 1.1 nisimura * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 18 1.1 nisimura * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 19 1.1 nisimura * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 20 1.1 nisimura * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 21 1.1 nisimura * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 22 1.1 nisimura * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 23 1.1 nisimura * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 24 1.1 nisimura * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 25 1.1 nisimura * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 26 1.1 nisimura * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 27 1.1 nisimura * POSSIBILITY OF SUCH DAMAGE. 28 1.1 nisimura */ 29 1.1 nisimura 30 1.1 nisimura #include <sys/cdefs.h> 31 1.1 nisimura #include <sys/param.h> 32 1.1 nisimura #include <sys/device.h> 33 1.1 nisimura #include <sys/kmem.h> 34 1.1 nisimura 35 1.1 nisimura #include <sys/bus.h> 36 1.1 nisimura 37 1.1 nisimura #include <arch/arm/s3c2xx0/s3c2440_dma.h> 38 1.1 nisimura #include <arch/arm/s3c2xx0/s3c2xx0var.h> 39 1.1 nisimura #include <arch/arm/s3c2xx0/s3c2440reg.h> 40 1.1 nisimura #include <arch/arm/s3c2xx0/s3c2440_i2s.h> 41 1.1 nisimura 42 1.1 nisimura /*#define S3C2440_I2S_DEBUG*/ 43 1.1 nisimura 44 1.1 nisimura #ifdef S3C2440_I2S_DEBUG 45 1.1 nisimura #define DPRINTF(x) do {printf x; } while (/*CONSTCOND*/0) 46 1.1 nisimura #else 47 1.1 nisimura #define DPRINTF(s) do {} while (/*CONSTCOND*/0) 48 1.1 nisimura #endif 49 1.1 nisimura 50 1.1 nisimura struct s3c2440_i2s_softc { 51 1.1 nisimura device_t sc_dev; 52 1.1 nisimura kmutex_t *sc_intr_lock; 53 1.1 nisimura bus_space_tag_t sc_iot; 54 1.1 nisimura bus_space_handle_t sc_i2s_ioh; 55 1.1 nisimura 56 1.1 nisimura int sc_master_clock; 57 1.1 nisimura int sc_serial_clock; 58 1.1 nisimura int sc_dir; 59 1.1 nisimura int sc_sample_width; 60 1.1 nisimura int sc_bus_format; 61 1.1 nisimura 62 1.1 nisimura bus_dma_segment_t sc_dr; 63 1.1 nisimura }; 64 1.1 nisimura 65 1.1 nisimura static void s3c2440_i2s_xfer_complete(dmac_xfer_t, void *); 66 1.1 nisimura 67 1.2 chs static int s3c2440_i2s_match(device_t, cfdata_t, void *); 68 1.2 chs static void s3c2440_i2s_attach(device_t, device_t , void *); 69 1.2 chs static int s3c2440_i2s_search(device_t, cfdata_t, const int *, void *); 70 1.3 msaitoh static int s3c2440_i2s_print(void *, const char *); 71 1.1 nisimura static int s3c2440_i2s_init(struct s3c2440_i2s_softc*); 72 1.1 nisimura 73 1.1 nisimura CFATTACH_DECL_NEW(ssiis, sizeof(struct s3c2440_i2s_softc), s3c2440_i2s_match, 74 1.1 nisimura s3c2440_i2s_attach, NULL, NULL); 75 1.1 nisimura 76 1.1 nisimura int 77 1.2 chs s3c2440_i2s_match(device_t parent, cfdata_t match, void *aux) 78 1.1 nisimura { 79 1.1 nisimura 80 1.1 nisimura return 1; 81 1.1 nisimura } 82 1.1 nisimura 83 1.1 nisimura void 84 1.2 chs s3c2440_i2s_attach(device_t parent, device_t self, void *aux) 85 1.1 nisimura { 86 1.1 nisimura struct s3c2440_i2s_softc *sc = device_private(self); 87 1.1 nisimura DPRINTF(("%s\n", __func__)); 88 1.1 nisimura 89 1.1 nisimura sc->sc_dev = self; 90 1.1 nisimura 91 1.1 nisimura s3c2440_i2s_init(sc); 92 1.1 nisimura 93 1.1 nisimura printf("\n"); 94 1.1 nisimura 95 1.5 thorpej config_search(self, NULL, 96 1.6 thorpej CFARGS(.search = s3c2440_i2s_search)); 97 1.1 nisimura } 98 1.1 nisimura 99 1.1 nisimura static int 100 1.1 nisimura s3c2440_i2s_print(void *aux, const char *name) 101 1.1 nisimura { 102 1.1 nisimura return UNCONF; 103 1.1 nisimura } 104 1.1 nisimura 105 1.1 nisimura static int 106 1.3 msaitoh s3c2440_i2s_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) 107 1.1 nisimura { 108 1.1 nisimura struct s3c2440_i2s_attach_args ia; 109 1.1 nisimura DPRINTF(("%s\n", __func__)); 110 1.1 nisimura 111 1.1 nisimura ia.i2sa_handle = device_private(parent); 112 1.1 nisimura 113 1.5 thorpej if (config_probe(parent, cf, &ia)) 114 1.6 thorpej config_attach(parent, cf, &ia, s3c2440_i2s_print, CFARGS_NONE); 115 1.1 nisimura 116 1.1 nisimura return 1; 117 1.1 nisimura } 118 1.1 nisimura 119 1.1 nisimura void 120 1.1 nisimura s3c2440_i2s_set_intr_lock(void *handle, kmutex_t *sc_intr_lock) 121 1.1 nisimura { 122 1.1 nisimura struct s3c2440_i2s_softc *sc = handle; 123 1.1 nisimura 124 1.1 nisimura sc->sc_intr_lock = sc_intr_lock; 125 1.1 nisimura } 126 1.1 nisimura 127 1.1 nisimura int 128 1.1 nisimura s3c2440_i2s_init(struct s3c2440_i2s_softc *i2s_sc) 129 1.1 nisimura { 130 1.1 nisimura struct s3c2xx0_softc *sc = s3c2xx0_softc; /* Shortcut */ 131 1.1 nisimura uint32_t reg; 132 1.1 nisimura 133 1.1 nisimura i2s_sc->sc_iot = sc->sc_iot; 134 1.1 nisimura 135 1.1 nisimura if (bus_space_map(sc->sc_iot, S3C2440_IIS_BASE, S3C24X0_IIS_SIZE, 0, 136 1.1 nisimura &i2s_sc->sc_i2s_ioh)) { 137 1.1 nisimura printf("Failed to map I2S registers\n"); 138 1.1 nisimura return ENOMEM; 139 1.1 nisimura } 140 1.1 nisimura 141 1.1 nisimura i2s_sc->sc_master_clock = 0; 142 1.1 nisimura i2s_sc->sc_serial_clock = 48; 143 1.1 nisimura i2s_sc->sc_dir = 0; 144 1.1 nisimura i2s_sc->sc_sample_width = 0; 145 1.1 nisimura i2s_sc->sc_bus_format = 0; 146 1.1 nisimura 147 1.1 nisimura reg = bus_space_read_4(sc->sc_iot, sc->sc_clkman_ioh, CLKMAN_CLKCON); 148 1.1 nisimura bus_space_write_4(sc->sc_iot, sc->sc_clkman_ioh, CLKMAN_CLKCON, reg | CLKCON_IIS); 149 1.1 nisimura 150 1.1 nisimura /* Setup GPIO pins to use I2S */ 151 1.1 nisimura reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, GPIO_PECON); 152 1.1 nisimura reg = GPIO_SET_FUNC(reg, 0, 2); 153 1.1 nisimura reg = GPIO_SET_FUNC(reg, 1, 2); 154 1.1 nisimura reg = GPIO_SET_FUNC(reg, 2, 2); 155 1.1 nisimura reg = GPIO_SET_FUNC(reg, 3, 2); 156 1.1 nisimura reg = GPIO_SET_FUNC(reg, 4, 2); 157 1.1 nisimura bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, GPIO_PECON, reg); 158 1.1 nisimura 159 1.8 andvar /* Disable Pull-up resistor for all I2S pins */ 160 1.1 nisimura reg = bus_space_read_4(sc->sc_iot, sc->sc_gpio_ioh, GPIO_PEUP); 161 1.1 nisimura 162 1.1 nisimura reg = GPIO_SET_DATA(reg, 0, 1); 163 1.1 nisimura reg = GPIO_SET_DATA(reg, 1, 1); 164 1.1 nisimura reg = GPIO_SET_DATA(reg, 2, 1); 165 1.1 nisimura reg = GPIO_SET_DATA(reg, 3, 1); 166 1.1 nisimura reg = GPIO_SET_DATA(reg, 4, 1); 167 1.1 nisimura 168 1.1 nisimura bus_space_write_4(sc->sc_iot, sc->sc_gpio_ioh, GPIO_PEUP, reg); 169 1.1 nisimura 170 1.1 nisimura i2s_sc->sc_dr.ds_addr = S3C2440_IIS_BASE + IISFIFO; 171 1.1 nisimura i2s_sc->sc_dr.ds_len = 4; 172 1.1 nisimura 173 1.1 nisimura return 0; 174 1.1 nisimura } 175 1.1 nisimura 176 1.1 nisimura void 177 1.1 nisimura s3c2440_i2s_set_direction(void *handle, int direction) 178 1.1 nisimura { 179 1.1 nisimura struct s3c2440_i2s_softc *sc = handle; 180 1.1 nisimura sc->sc_dir = direction; 181 1.1 nisimura } 182 1.1 nisimura 183 1.1 nisimura void 184 1.1 nisimura s3c2440_i2s_set_sample_rate(void *handle, int sample_rate) 185 1.1 nisimura { 186 1.1 nisimura struct s3c2440_i2s_softc *sc = handle; 187 1.1 nisimura int codecClock; 188 1.1 nisimura int codecClockPrescaler; 189 1.1 nisimura int pclk = s3c2xx0_softc->sc_pclk; /* Peripherical Clock in Hz*/ 190 1.1 nisimura 191 1.1 nisimura DPRINTF(("%s\n", __func__)); 192 1.1 nisimura 193 1.1 nisimura /* TODO: Add selection of 256fs when needed */ 194 1.1 nisimura sc->sc_master_clock = 384; 195 1.1 nisimura 196 1.1 nisimura codecClock = sample_rate * sc->sc_master_clock; 197 1.1 nisimura codecClockPrescaler = pclk/codecClock; 198 1.1 nisimura 199 1.1 nisimura DPRINTF(("CODEC Clock: %d Hz\n", codecClock)); 200 1.1 nisimura DPRINTF(("Prescaler: %d\n", codecClockPrescaler)); 201 1.1 nisimura DPRINTF(("Actual CODEC Clock: %d Hz\n", pclk/(codecClockPrescaler+1))); 202 1.1 nisimura DPRINTF(("Actual Sampling rate: %d Hz\n", 203 1.1 nisimura (pclk/(codecClockPrescaler+1))/sc->sc_master_clock)); 204 1.1 nisimura 205 1.1 nisimura bus_space_write_4(sc->sc_iot, sc->sc_i2s_ioh, IISPSR, 206 1.1 nisimura IISPSR_PRESCALER_A(codecClockPrescaler) | 207 1.1 nisimura IISPSR_PRESCALER_B(codecClockPrescaler)); 208 1.1 nisimura } 209 1.1 nisimura 210 1.1 nisimura void 211 1.1 nisimura s3c2440_i2s_set_sample_width(void *handle, int width) 212 1.1 nisimura { 213 1.1 nisimura struct s3c2440_i2s_softc *sc = handle; 214 1.1 nisimura sc->sc_sample_width = width; 215 1.1 nisimura } 216 1.1 nisimura 217 1.1 nisimura void 218 1.1 nisimura s3c2440_i2s_set_bus_format(void *handle, int format) 219 1.1 nisimura { 220 1.1 nisimura struct s3c2440_i2s_softc *sc = handle; 221 1.1 nisimura 222 1.1 nisimura sc->sc_bus_format = format; 223 1.1 nisimura } 224 1.1 nisimura 225 1.1 nisimura int 226 1.1 nisimura s3c2440_i2s_commit(void *handle) 227 1.1 nisimura { 228 1.1 nisimura uint32_t iisfcon, iiscon, iismod; 229 1.1 nisimura struct s3c2440_i2s_softc *sc = handle; 230 1.1 nisimura 231 1.1 nisimura DPRINTF(("%s\n", __func__)); 232 1.1 nisimura 233 1.1 nisimura iisfcon = 0; 234 1.1 nisimura iiscon = IISCON_IFACE_EN | IISCON_PRESCALER_EN; 235 1.1 nisimura iismod = 0; 236 1.1 nisimura 237 1.1 nisimura if ( (sc->sc_dir & S3C2440_I2S_TRANSMIT) ) { 238 1.1 nisimura iisfcon |= IISFCON_TX_DMA_EN | IISFCON_TX_FIFO_EN; 239 1.1 nisimura iiscon |= IISCON_TX_DMA_EN; 240 1.1 nisimura iismod |= IISMOD_MODE_TRANSMIT; 241 1.1 nisimura } 242 1.1 nisimura 243 1.1 nisimura if ( (sc->sc_dir & S3C2440_I2S_RECEIVE) ) { 244 1.1 nisimura iisfcon |= IISFCON_RX_DMA_EN | IISFCON_RX_FIFO_EN; 245 1.1 nisimura iiscon |= IISCON_RX_DMA_EN; 246 1.1 nisimura iismod |= IISMOD_MODE_RECEIVE; 247 1.1 nisimura } 248 1.1 nisimura 249 1.1 nisimura if (iisfcon == 0) { 250 1.1 nisimura return EINVAL; 251 1.1 nisimura } 252 1.1 nisimura 253 1.1 nisimura 254 1.1 nisimura if (sc->sc_bus_format == S3C2440_I2S_BUS_MSB) 255 1.1 nisimura iismod |= IISMOD_IFACE_MSB; 256 1.1 nisimura 257 1.1 nisimura switch (sc->sc_master_clock) { 258 1.1 nisimura case 256: 259 1.1 nisimura iismod |= IISMOD_MASTER_FREQ256; 260 1.1 nisimura break; 261 1.1 nisimura case 384: 262 1.1 nisimura iismod |= IISMOD_MASTER_FREQ384; 263 1.1 nisimura break; 264 1.1 nisimura default: 265 1.1 nisimura return EINVAL; 266 1.1 nisimura 267 1.1 nisimura } 268 1.1 nisimura 269 1.1 nisimura switch (sc->sc_serial_clock) { 270 1.1 nisimura case 16: 271 1.1 nisimura iismod |= IISMOD_SERIAL_FREQ16; 272 1.1 nisimura break; 273 1.1 nisimura case 32: 274 1.1 nisimura iismod |= IISMOD_SERIAL_FREQ32; 275 1.1 nisimura break; 276 1.1 nisimura case 48: 277 1.1 nisimura iismod |= IISMOD_SERIAL_FREQ48; 278 1.1 nisimura break; 279 1.1 nisimura default: 280 1.1 nisimura return EINVAL; 281 1.1 nisimura } 282 1.1 nisimura 283 1.1 nisimura if (sc->sc_sample_width == 16) 284 1.1 nisimura iismod |= IISMOD_16BIT; 285 1.1 nisimura 286 1.1 nisimura bus_space_write_4(sc->sc_iot, sc->sc_i2s_ioh, IISFCON, iisfcon); 287 1.1 nisimura bus_space_write_4(sc->sc_iot, sc->sc_i2s_ioh, IISMOD, iismod); 288 1.1 nisimura bus_space_write_4(sc->sc_iot, sc->sc_i2s_ioh, IISCON, iiscon); 289 1.1 nisimura 290 1.1 nisimura return 0; 291 1.1 nisimura } 292 1.1 nisimura 293 1.1 nisimura int 294 1.1 nisimura s3c2440_i2s_disable(void *handle) 295 1.1 nisimura { 296 1.1 nisimura return 0; 297 1.1 nisimura } 298 1.1 nisimura 299 1.1 nisimura int 300 1.1 nisimura s3c2440_i2s_get_master_clock(void *handle) 301 1.1 nisimura { 302 1.1 nisimura struct s3c2440_i2s_softc *sc = handle; 303 1.1 nisimura return sc->sc_master_clock; 304 1.1 nisimura } 305 1.1 nisimura 306 1.1 nisimura int 307 1.1 nisimura s3c2440_i2s_get_serial_clock(void *handle) 308 1.1 nisimura { 309 1.1 nisimura struct s3c2440_i2s_softc *sc = handle; 310 1.1 nisimura 311 1.1 nisimura return sc->sc_serial_clock; 312 1.1 nisimura } 313 1.1 nisimura 314 1.1 nisimura int 315 1.1 nisimura s3c2440_i2s_alloc(void *handle, 316 1.1 nisimura int direction, size_t size, int flags, 317 1.1 nisimura s3c2440_i2s_buf_t *out) 318 1.1 nisimura { 319 1.1 nisimura int retval = 0; 320 1.1 nisimura struct s3c2xx0_softc *sc = s3c2xx0_softc; /* Shortcut */ 321 1.1 nisimura s3c2440_i2s_buf_t buf; 322 1.1 nisimura 323 1.1 nisimura DPRINTF(("%s\n", __func__)); 324 1.1 nisimura 325 1.4 chs *out = kmem_alloc(sizeof(struct s3c2440_i2s_buf), KM_SLEEP); 326 1.1 nisimura buf = *out; 327 1.1 nisimura buf->i2b_parent = handle; 328 1.1 nisimura buf->i2b_size = size; 329 1.1 nisimura buf->i2b_nsegs = S3C2440_I2S_BUF_MAX_SEGS; 330 1.1 nisimura buf->i2b_xfer = NULL; 331 1.1 nisimura buf->i2b_cb = NULL; 332 1.1 nisimura buf->i2b_cb_cookie = NULL; 333 1.1 nisimura 334 1.1 nisimura /* We first allocate some DMA-friendly memory for the buffer... */ 335 1.1 nisimura retval = bus_dmamem_alloc(sc->sc_dmat, buf->i2b_size, NBPG, 0, 336 1.1 nisimura buf->i2b_segs, buf->i2b_nsegs, &buf->i2b_nsegs, 337 1.4 chs BUS_DMA_WAITOK); 338 1.1 nisimura if (retval != 0) { 339 1.1 nisimura printf("%s: Failed to allocate DMA memory\n", __func__); 340 1.1 nisimura goto cleanup_dealloc; 341 1.1 nisimura } 342 1.1 nisimura 343 1.1 nisimura DPRINTF(("%s: Using %d DMA segments\n", __func__, buf->i2b_nsegs)); 344 1.1 nisimura 345 1.1 nisimura retval = bus_dmamem_map(sc->sc_dmat, buf->i2b_segs, buf->i2b_nsegs, 346 1.4 chs buf->i2b_size, &buf->i2b_addr, BUS_DMA_WAITOK); 347 1.1 nisimura 348 1.1 nisimura if (retval != 0) { 349 1.1 nisimura printf("%s: Failed to map DMA memory\n", __func__); 350 1.1 nisimura goto cleanup_dealloc_dma; 351 1.1 nisimura } 352 1.1 nisimura 353 1.1 nisimura DPRINTF(("%s: Playback DMA buffer mapped at %p\n", __func__, 354 1.1 nisimura buf->i2b_addr)); 355 1.1 nisimura 356 1.1 nisimura /* XXX: Not sure if nsegments is really 1...*/ 357 1.1 nisimura retval = bus_dmamap_create(sc->sc_dmat, buf->i2b_size, 1, 358 1.4 chs buf->i2b_size, 0, BUS_DMA_WAITOK, 359 1.1 nisimura &buf->i2b_dmamap); 360 1.1 nisimura if (retval != 0) { 361 1.1 nisimura printf("%s: Failed to create DMA map\n", __func__); 362 1.1 nisimura goto cleanup_unmap_dma; 363 1.1 nisimura } 364 1.1 nisimura 365 1.1 nisimura DPRINTF(("%s: DMA map created successfully\n", __func__)); 366 1.1 nisimura 367 1.4 chs buf->i2b_xfer = s3c2440_dmac_allocate_xfer(); 368 1.1 nisimura 369 1.1 nisimura return 0; 370 1.1 nisimura cleanup_unmap_dma: 371 1.1 nisimura bus_dmamem_unmap(sc->sc_dmat, &buf->i2b_addr, buf->i2b_size); 372 1.1 nisimura cleanup_dealloc_dma: 373 1.1 nisimura bus_dmamem_free(sc->sc_dmat, buf->i2b_segs, buf->i2b_nsegs); 374 1.1 nisimura cleanup_dealloc: 375 1.1 nisimura kmem_free(*out, sizeof(struct s3c2440_i2s_buf)); 376 1.1 nisimura return retval; 377 1.1 nisimura } 378 1.1 nisimura 379 1.1 nisimura void 380 1.1 nisimura s3c2440_i2s_free(s3c2440_i2s_buf_t buf) 381 1.1 nisimura { 382 1.1 nisimura struct s3c2xx0_softc *sc = s3c2xx0_softc; /* Shortcut */ 383 1.1 nisimura 384 1.1 nisimura if (buf->i2b_xfer != NULL) { 385 1.1 nisimura s3c2440_dmac_free_xfer(buf->i2b_xfer); 386 1.1 nisimura } 387 1.1 nisimura 388 1.1 nisimura bus_dmamap_unload(sc->sc_dmat, buf->i2b_dmamap); 389 1.1 nisimura bus_dmamap_destroy(sc->sc_dmat, buf->i2b_dmamap); 390 1.1 nisimura bus_dmamem_unmap(sc->sc_dmat, &buf->i2b_addr, buf->i2b_size); 391 1.1 nisimura bus_dmamem_free(sc->sc_dmat, buf->i2b_segs, buf->i2b_nsegs); 392 1.1 nisimura kmem_free(buf, sizeof(struct s3c2440_i2s_buf)); 393 1.1 nisimura } 394 1.1 nisimura 395 1.1 nisimura int 396 1.1 nisimura s3c2440_i2s_output(s3c2440_i2s_buf_t buf, void *block, int bsize, 397 1.1 nisimura void (*callback)(void*), void *cb_cookie) 398 1.1 nisimura { 399 1.1 nisimura struct s3c2xx0_softc *sc = s3c2xx0_softc; /* Shortcut */ 400 1.1 nisimura struct s3c2440_i2s_softc *i2s = buf->i2b_parent; 401 1.1 nisimura int retval; 402 1.1 nisimura dmac_xfer_t xfer = buf->i2b_xfer; 403 1.1 nisimura 404 1.1 nisimura retval = bus_dmamap_load(sc->sc_dmat, buf->i2b_dmamap, block, 405 1.1 nisimura bsize, NULL, BUS_DMA_NOWAIT); 406 1.1 nisimura if (retval != 0) { 407 1.1 nisimura printf("Failed to load DMA map\n"); 408 1.1 nisimura return retval; 409 1.1 nisimura } 410 1.1 nisimura 411 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_bus_type = DMAC_BUS_TYPE_PERIPHERAL; 412 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_increment = FALSE; 413 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_nsegs = 1; 414 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_dma_segs = &i2s->sc_dr; 415 1.1 nisimura 416 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_bus_type = DMAC_BUS_TYPE_SYSTEM; 417 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_increment = TRUE; 418 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_nsegs = buf->i2b_dmamap->dm_nsegs; 419 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_dma_segs = buf->i2b_dmamap->dm_segs; 420 1.1 nisimura 421 1.1 nisimura xfer->dx_peripheral = DMAC_PERIPH_I2SSDO; 422 1.1 nisimura 423 1.1 nisimura if (i2s->sc_sample_width == 16) 424 1.1 nisimura xfer->dx_xfer_width = DMAC_XFER_WIDTH_16BIT; 425 1.1 nisimura else if (i2s->sc_sample_width == 8) 426 1.1 nisimura xfer->dx_xfer_width = DMAC_XFER_WIDTH_8BIT; 427 1.1 nisimura 428 1.1 nisimura xfer->dx_done = s3c2440_i2s_xfer_complete; 429 1.1 nisimura xfer->dx_cookie = buf; 430 1.1 nisimura xfer->dx_xfer_mode = DMAC_XFER_MODE_HANDSHAKE; 431 1.1 nisimura 432 1.1 nisimura buf->i2b_cb = callback; 433 1.1 nisimura buf->i2b_cb_cookie = cb_cookie; 434 1.1 nisimura 435 1.1 nisimura s3c2440_dmac_start_xfer(buf->i2b_xfer); 436 1.1 nisimura 437 1.1 nisimura return 0; 438 1.1 nisimura } 439 1.1 nisimura 440 1.1 nisimura int 441 1.1 nisimura s3c2440_i2s_halt_output(s3c2440_i2s_buf_t buf) 442 1.1 nisimura { 443 1.1 nisimura /*int retval;*/ 444 1.1 nisimura struct s3c2xx0_softc *sc = s3c2xx0_softc; /* Shortcut */ 445 1.1 nisimura 446 1.1 nisimura DPRINTF(("Aborting DMA transfer\n")); 447 1.1 nisimura /*do { 448 1.1 nisimura retval =*/ s3c2440_dmac_abort_xfer(buf->i2b_xfer); 449 1.1 nisimura /*} while(retval != 0);*/ 450 1.1 nisimura DPRINTF(("Aborting DMA transfer: SUCCESS\n")); 451 1.1 nisimura 452 1.1 nisimura bus_dmamap_unload(sc->sc_dmat, buf->i2b_dmamap); 453 1.1 nisimura 454 1.1 nisimura return 0; 455 1.1 nisimura } 456 1.1 nisimura 457 1.1 nisimura int 458 1.1 nisimura s3c2440_i2s_input(s3c2440_i2s_buf_t buf, void *block, int bsize, 459 1.1 nisimura void (*callback)(void*), void *cb_cookie) 460 1.1 nisimura { 461 1.1 nisimura struct s3c2xx0_softc *sc = s3c2xx0_softc; /* Shortcut */ 462 1.1 nisimura struct s3c2440_i2s_softc *i2s = buf->i2b_parent; 463 1.1 nisimura int retval; 464 1.1 nisimura dmac_xfer_t xfer = buf->i2b_xfer; 465 1.1 nisimura 466 1.1 nisimura retval = bus_dmamap_load(sc->sc_dmat, buf->i2b_dmamap, block, 467 1.1 nisimura bsize, NULL, BUS_DMA_NOWAIT); 468 1.1 nisimura if (retval != 0) { 469 1.1 nisimura printf("Failed to load DMA map\n"); 470 1.1 nisimura return retval; 471 1.1 nisimura } 472 1.1 nisimura 473 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_bus_type = DMAC_BUS_TYPE_PERIPHERAL; 474 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_increment = FALSE; 475 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_nsegs = 1; 476 1.1 nisimura xfer->dx_desc[DMAC_DESC_SRC].xd_dma_segs = &i2s->sc_dr; 477 1.1 nisimura 478 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_bus_type = DMAC_BUS_TYPE_SYSTEM; 479 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_increment = TRUE; 480 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_nsegs = buf->i2b_dmamap->dm_nsegs; 481 1.1 nisimura xfer->dx_desc[DMAC_DESC_DST].xd_dma_segs = buf->i2b_dmamap->dm_segs; 482 1.1 nisimura 483 1.1 nisimura xfer->dx_peripheral = DMAC_PERIPH_I2SSDI; 484 1.1 nisimura 485 1.1 nisimura if (i2s->sc_sample_width == 16) 486 1.1 nisimura xfer->dx_xfer_width = DMAC_XFER_WIDTH_16BIT; 487 1.1 nisimura else if (i2s->sc_sample_width == 8) 488 1.1 nisimura xfer->dx_xfer_width = DMAC_XFER_WIDTH_8BIT; 489 1.1 nisimura 490 1.1 nisimura xfer->dx_done = s3c2440_i2s_xfer_complete; 491 1.1 nisimura xfer->dx_cookie = buf; 492 1.1 nisimura xfer->dx_xfer_mode = DMAC_XFER_MODE_HANDSHAKE; 493 1.1 nisimura 494 1.1 nisimura buf->i2b_cb = callback; 495 1.1 nisimura buf->i2b_cb_cookie = cb_cookie; 496 1.1 nisimura 497 1.1 nisimura s3c2440_dmac_start_xfer(buf->i2b_xfer); 498 1.1 nisimura 499 1.1 nisimura return 0; 500 1.1 nisimura } 501 1.1 nisimura 502 1.1 nisimura static void 503 1.1 nisimura s3c2440_i2s_xfer_complete(dmac_xfer_t xfer, void *cookie) 504 1.1 nisimura { 505 1.1 nisimura struct s3c2xx0_softc *sc = s3c2xx0_softc; /* Shortcut */ 506 1.1 nisimura s3c2440_i2s_buf_t buf = cookie; 507 1.1 nisimura struct s3c2440_i2s_softc *i2s = buf->i2b_parent; 508 1.1 nisimura 509 1.1 nisimura bus_dmamap_unload(sc->sc_dmat, buf->i2b_dmamap); 510 1.1 nisimura 511 1.1 nisimura mutex_spin_enter(i2s->sc_intr_lock); 512 1.1 nisimura (buf->i2b_cb)(buf->i2b_cb_cookie); 513 1.1 nisimura mutex_spin_exit(i2s->sc_intr_lock); 514 1.1 nisimura } 515