Annotation of sys/arch/macppc/dev/i2s.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: i2s.c,v 1.8 2007/04/22 22:31:14 deraadt Exp $ */
! 2: /* $NetBSD: i2s.c,v 1.1 2003/12/27 02:19:34 grant Exp $ */
! 3:
! 4: /*-
! 5: * Copyright (c) 2002 Tsubai Masanari. 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: * 3. The name of the author may not be used to endorse or promote products
! 16: * derived from this software without specific prior written permission.
! 17: *
! 18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
! 27: * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 28: */
! 29:
! 30: #include <sys/param.h>
! 31: #include <sys/audioio.h>
! 32: #include <sys/device.h>
! 33: #include <sys/malloc.h>
! 34: #include <sys/systm.h>
! 35:
! 36: #include <dev/auconv.h>
! 37: #include <dev/audio_if.h>
! 38: #include <dev/mulaw.h>
! 39: #include <dev/ofw/openfirm.h>
! 40: #include <macppc/dev/dbdma.h>
! 41:
! 42: #include <uvm/uvm_extern.h>
! 43:
! 44: #include <machine/autoconf.h>
! 45: #include <machine/pio.h>
! 46:
! 47: #include <macppc/dev/i2svar.h>
! 48: #include <macppc/dev/i2sreg.h>
! 49:
! 50: #ifdef I2S_DEBUG
! 51: # define DPRINTF(x) printf x
! 52: #else
! 53: # define DPRINTF(x)
! 54: #endif
! 55:
! 56: struct i2s_mode *i2s_find_mode(u_int, u_int, u_int);
! 57: void i2s_cs16mts(void *, u_char *, int);
! 58:
! 59: static int gpio_read(char *);
! 60: static void gpio_write(char *, int);
! 61: void i2s_mute_speaker(struct i2s_softc *, int);
! 62: void i2s_mute_headphone(struct i2s_softc *, int);
! 63: void i2s_mute_lineout(struct i2s_softc *, int);
! 64: int i2s_cint(void *);
! 65: u_char *i2s_gpio_map(struct i2s_softc *, char *, int *);
! 66: void i2s_init(struct i2s_softc *, int);
! 67:
! 68: static void mono16_to_stereo16(void *, u_char *, int);
! 69: static void swap_bytes_mono16_to_stereo16(void *, u_char *, int);
! 70:
! 71: /* XXX */
! 72: void keylargo_fcr_enable(int, u_int32_t);
! 73: void keylargo_fcr_disable(int, u_int32_t);
! 74:
! 75: struct cfdriver i2s_cd = {
! 76: NULL, "i2s", DV_DULL
! 77: };
! 78:
! 79: static u_char *amp_mute;
! 80: static u_char *headphone_mute;
! 81: static u_char *lineout_mute;
! 82: static u_char *audio_hw_reset;
! 83: static u_char *headphone_detect;
! 84: static int headphone_detect_active;
! 85: static u_char *lineout_detect;
! 86: static int lineout_detect_active;
! 87:
! 88: /* GPIO bits */
! 89: #define GPIO_OUTSEL 0xf0 /* Output select */
! 90: /* 0x00 GPIO bit0 is output
! 91: 0x10 media-bay power
! 92: 0x20 reserved
! 93: 0x30 MPIC */
! 94:
! 95: #define GPIO_ALTOE 0x08 /* Alternate output enable */
! 96: /* 0x00 Use DDR
! 97: 0x08 Use output select */
! 98:
! 99: #define GPIO_DDR 0x04 /* Data direction */
! 100: #define GPIO_DDR_OUTPUT 0x04 /* Output */
! 101: #define GPIO_DDR_INPUT 0x00 /* Input */
! 102:
! 103: #define GPIO_LEVEL 0x02 /* Pin level (RO) */
! 104:
! 105: #define GPIO_DATA 0x01 /* Data */
! 106:
! 107: void
! 108: i2s_attach(struct device *parent, struct i2s_softc *sc, struct confargs *ca)
! 109: {
! 110: int cirq, oirq, iirq, cirq_type, oirq_type, iirq_type;
! 111: u_int32_t reg[6], intr[6];
! 112:
! 113: sc->sc_node = OF_child(ca->ca_node);
! 114: sc->sc_baseaddr = ca->ca_baseaddr;
! 115:
! 116: OF_getprop(sc->sc_node, "reg", reg, sizeof reg);
! 117: reg[0] += sc->sc_baseaddr;
! 118: reg[2] += sc->sc_baseaddr;
! 119: reg[4] += sc->sc_baseaddr;
! 120:
! 121: sc->sc_reg = mapiodev(reg[0], reg[1]);
! 122:
! 123: sc->sc_dmat = ca->ca_dmat;
! 124: sc->sc_odma = mapiodev(reg[2], reg[3]); /* out */
! 125: sc->sc_idma = mapiodev(reg[4], reg[5]); /* in */
! 126: sc->sc_odbdma = dbdma_alloc(sc->sc_dmat, I2S_DMALIST_MAX);
! 127: sc->sc_odmacmd = sc->sc_odbdma->d_addr;
! 128: sc->sc_idbdma = dbdma_alloc(sc->sc_dmat, I2S_DMALIST_MAX);
! 129: sc->sc_idmacmd = sc->sc_idbdma->d_addr;
! 130:
! 131: OF_getprop(sc->sc_node, "interrupts", intr, sizeof intr);
! 132: cirq = intr[0];
! 133: oirq = intr[2];
! 134: iirq = intr[4];
! 135: cirq_type = intr[1] ? IST_LEVEL : IST_EDGE;
! 136: oirq_type = intr[3] ? IST_LEVEL : IST_EDGE;
! 137: iirq_type = intr[5] ? IST_LEVEL : IST_EDGE;
! 138:
! 139: /* intr_establish(cirq, cirq_type, IPL_AUDIO, i2s_intr, sc); */
! 140: mac_intr_establish(parent, oirq, oirq_type, IPL_AUDIO, i2s_intr,
! 141: sc, sc->sc_dev.dv_xname);
! 142: /* intr_establish(iirq, iirq_type, IPL_AUDIO, i2s_intr, sc); */
! 143:
! 144: printf(": irq %d,%d,%d\n", cirq, oirq, iirq);
! 145:
! 146: i2s_set_rate(sc, 44100);
! 147: i2s_gpio_init(sc, ca->ca_node, parent);
! 148: }
! 149:
! 150: int
! 151: i2s_intr(v)
! 152: void *v;
! 153: {
! 154: struct i2s_softc *sc = v;
! 155: struct dbdma_command *cmd = sc->sc_odmap;
! 156: u_int16_t c, status;
! 157:
! 158: /* if not set we are not running */
! 159: if (!cmd)
! 160: return (0);
! 161: DPRINTF(("i2s_intr: cmd %x\n", cmd));
! 162:
! 163: c = in16rb(&cmd->d_command);
! 164: status = in16rb(&cmd->d_status);
! 165:
! 166: if (c >> 12 == DBDMA_CMD_OUT_LAST)
! 167: sc->sc_odmap = sc->sc_odmacmd;
! 168: else
! 169: sc->sc_odmap++;
! 170:
! 171: if (c & (DBDMA_INT_ALWAYS << 4)) {
! 172: cmd->d_status = 0;
! 173: if (status) /* status == 0x8400 */
! 174: if (sc->sc_ointr)
! 175: (*sc->sc_ointr)(sc->sc_oarg);
! 176: }
! 177:
! 178: return 1;
! 179: }
! 180:
! 181: int
! 182: i2s_open(h, flags)
! 183: void *h;
! 184: int flags;
! 185: {
! 186: return 0;
! 187: }
! 188:
! 189: /*
! 190: * Close function is called at splaudio().
! 191: */
! 192: void
! 193: i2s_close(h)
! 194: void *h;
! 195: {
! 196: struct i2s_softc *sc = h;
! 197:
! 198: i2s_halt_output(sc);
! 199: i2s_halt_input(sc);
! 200:
! 201: sc->sc_ointr = 0;
! 202: sc->sc_iintr = 0;
! 203: }
! 204:
! 205: int
! 206: i2s_query_encoding(h, ae)
! 207: void *h;
! 208: struct audio_encoding *ae;
! 209: {
! 210: int err = 0;
! 211:
! 212: switch (ae->index) {
! 213: case 0:
! 214: strlcpy(ae->name, AudioEslinear, sizeof(ae->name));
! 215: ae->encoding = AUDIO_ENCODING_SLINEAR;
! 216: ae->precision = 16;
! 217: ae->flags = 0;
! 218: break;
! 219: case 1:
! 220: strlcpy(ae->name, AudioEslinear_be, sizeof(ae->name));
! 221: ae->encoding = AUDIO_ENCODING_SLINEAR_BE;
! 222: ae->precision = 16;
! 223: ae->flags = 0;
! 224: break;
! 225: case 2:
! 226: strlcpy(ae->name, AudioEslinear_le, sizeof(ae->name));
! 227: ae->encoding = AUDIO_ENCODING_SLINEAR_LE;
! 228: ae->precision = 16;
! 229: ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 230: break;
! 231: case 3:
! 232: strlcpy(ae->name, AudioEulinear_be, sizeof(ae->name));
! 233: ae->encoding = AUDIO_ENCODING_ULINEAR_BE;
! 234: ae->precision = 16;
! 235: ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 236: break;
! 237: case 4:
! 238: strlcpy(ae->name, AudioEulinear_le, sizeof(ae->name));
! 239: ae->encoding = AUDIO_ENCODING_ULINEAR_LE;
! 240: ae->precision = 16;
! 241: ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 242: break;
! 243: case 5:
! 244: strlcpy(ae->name, AudioEmulaw, sizeof(ae->name));
! 245: ae->encoding = AUDIO_ENCODING_ULAW;
! 246: ae->precision = 8;
! 247: ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 248: break;
! 249: case 6:
! 250: strlcpy(ae->name, AudioEalaw, sizeof(ae->name));
! 251: ae->encoding = AUDIO_ENCODING_ALAW;
! 252: ae->precision = 8;
! 253: ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 254: break;
! 255: case 7:
! 256: strlcpy(ae->name, AudioEslinear, sizeof(ae->name));
! 257: ae->encoding = AUDIO_ENCODING_SLINEAR;
! 258: ae->precision = 8;
! 259: ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 260: break;
! 261: case 8:
! 262: strlcpy(ae->name, AudioEulinear, sizeof(ae->name));
! 263: ae->encoding = AUDIO_ENCODING_ULINEAR;
! 264: ae->precision = 8;
! 265: ae->flags = AUDIO_ENCODINGFLAG_EMULATED;
! 266: break;
! 267: default:
! 268: err = EINVAL;
! 269: break;
! 270: }
! 271: return (err);
! 272: }
! 273:
! 274: static void
! 275: mono16_to_stereo16(v, p, cc)
! 276: void *v;
! 277: u_char *p;
! 278: int cc;
! 279: {
! 280: int x;
! 281: int16_t *src, *dst;
! 282:
! 283: src = (void *)(p + cc);
! 284: dst = (void *)(p + cc * 2);
! 285: while (cc > 0) {
! 286: x = *--src;
! 287: *--dst = x;
! 288: *--dst = x;
! 289: cc -= 2;
! 290: }
! 291: }
! 292:
! 293: static void
! 294: swap_bytes_mono16_to_stereo16(v, p, cc)
! 295: void *v;
! 296: u_char *p;
! 297: int cc;
! 298: {
! 299: swap_bytes(v, p, cc);
! 300: mono16_to_stereo16(v, p, cc);
! 301: }
! 302:
! 303: void
! 304: i2s_cs16mts(void *v, u_char *p, int cc)
! 305: {
! 306: mono16_to_stereo16(v, p, cc);
! 307: change_sign16_be(v, p, cc * 2);
! 308: }
! 309:
! 310: struct i2s_mode {
! 311: u_int encoding;
! 312: u_int precision;
! 313: u_int channels;
! 314: void (*sw_code)(void *, u_char *, int);
! 315: int factor;
! 316: } i2s_modes[] = {
! 317: { AUDIO_ENCODING_SLINEAR_LE, 8, 1, linear8_to_linear16_be_mts, 4 },
! 318: { AUDIO_ENCODING_SLINEAR_LE, 8, 2, linear8_to_linear16_be, 2 },
! 319: { AUDIO_ENCODING_SLINEAR_LE, 16, 1, swap_bytes_mono16_to_stereo16, 2 },
! 320: { AUDIO_ENCODING_SLINEAR_LE, 16, 2, swap_bytes, 1 },
! 321: { AUDIO_ENCODING_SLINEAR_BE, 8, 1, linear8_to_linear16_be_mts, 4 },
! 322: { AUDIO_ENCODING_SLINEAR_BE, 8, 2, linear8_to_linear16_be, 2 },
! 323: { AUDIO_ENCODING_SLINEAR_BE, 16, 1, mono16_to_stereo16, 2 },
! 324: { AUDIO_ENCODING_SLINEAR_BE, 16, 2, NULL, 1 },
! 325: { AUDIO_ENCODING_ULINEAR_LE, 8, 1, ulinear8_to_linear16_be_mts, 4 },
! 326: { AUDIO_ENCODING_ULINEAR_LE, 8, 2, ulinear8_to_linear16_be, 2 },
! 327: { AUDIO_ENCODING_ULINEAR_LE, 16, 1, change_sign16_swap_bytes_le_mts, 2 },
! 328: { AUDIO_ENCODING_ULINEAR_LE, 16, 2, swap_bytes_change_sign16_be, 1 },
! 329: { AUDIO_ENCODING_ULINEAR_BE, 8, 1, ulinear8_to_linear16_be_mts, 4 },
! 330: { AUDIO_ENCODING_ULINEAR_BE, 8, 2, ulinear8_to_linear16_be, 2 },
! 331: { AUDIO_ENCODING_ULINEAR_BE, 16, 1, i2s_cs16mts, 2 },
! 332: { AUDIO_ENCODING_ULINEAR_BE, 16, 2, change_sign16_be, 1 }
! 333: };
! 334:
! 335:
! 336: struct i2s_mode *
! 337: i2s_find_mode(u_int encoding, u_int precision, u_int channels)
! 338: {
! 339: struct i2s_mode *m;
! 340: int i;
! 341:
! 342: for (i = 0; i < sizeof(i2s_modes)/sizeof(i2s_modes[0]); i++) {
! 343: m = &i2s_modes[i];
! 344: if (m->encoding == encoding &&
! 345: m->precision == precision &&
! 346: m->channels == channels)
! 347: return (m);
! 348: }
! 349: return (NULL);
! 350: }
! 351:
! 352: int
! 353: i2s_set_params(h, setmode, usemode, play, rec)
! 354: void *h;
! 355: int setmode, usemode;
! 356: struct audio_params *play, *rec;
! 357: {
! 358: struct i2s_mode *m;
! 359: struct i2s_softc *sc = h;
! 360: struct audio_params *p;
! 361: int mode;
! 362:
! 363: p = play; /* default to play */
! 364:
! 365: /*
! 366: * This device only has one clock, so make the sample rates match.
! 367: */
! 368: if (play->sample_rate != rec->sample_rate &&
! 369: usemode == (AUMODE_PLAY | AUMODE_RECORD)) {
! 370: if (setmode == AUMODE_PLAY) {
! 371: rec->sample_rate = play->sample_rate;
! 372: setmode |= AUMODE_RECORD;
! 373: } else if (setmode == AUMODE_RECORD) {
! 374: play->sample_rate = rec->sample_rate;
! 375: setmode |= AUMODE_PLAY;
! 376: } else
! 377: return EINVAL;
! 378: }
! 379:
! 380: for (mode = AUMODE_RECORD; mode != -1;
! 381: mode = mode == AUMODE_RECORD ? AUMODE_PLAY : -1) {
! 382: if ((setmode & mode) == 0)
! 383: continue;
! 384:
! 385: p = mode == AUMODE_PLAY ? play : rec;
! 386:
! 387: if (p->sample_rate < 4000 || p->sample_rate > 50000 ||
! 388: (p->precision != 8 && p->precision != 16) ||
! 389: (p->channels != 1 && p->channels != 2))
! 390: return EINVAL;
! 391:
! 392: switch (p->encoding) {
! 393: case AUDIO_ENCODING_SLINEAR_LE:
! 394: case AUDIO_ENCODING_SLINEAR_BE:
! 395: case AUDIO_ENCODING_ULINEAR_LE:
! 396: case AUDIO_ENCODING_ULINEAR_BE:
! 397: m = i2s_find_mode(p->encoding, p->precision,
! 398: p->channels);
! 399: if (m == NULL) {
! 400: printf("mode not found: %u/%u/%u\n",
! 401: p->encoding, p->precision, p->channels);
! 402: return (EINVAL);
! 403: }
! 404: p->factor = m->factor;
! 405: p->sw_code = m->sw_code;
! 406: break;
! 407:
! 408: case AUDIO_ENCODING_ULAW:
! 409: if (mode == AUMODE_PLAY) {
! 410: if (p->channels == 1) {
! 411: p->factor = 4;
! 412: p->sw_code = mulaw_to_slinear16_be_mts;
! 413: break;
! 414: }
! 415: if (p->channels == 2) {
! 416: p->factor = 2;
! 417: p->sw_code = mulaw_to_slinear16_be;
! 418: break;
! 419: }
! 420: } else
! 421: break; /* XXX */
! 422: return (EINVAL);
! 423:
! 424: case AUDIO_ENCODING_ALAW:
! 425: if (mode == AUMODE_PLAY) {
! 426: if (p->channels == 1) {
! 427: p->factor = 4;
! 428: p->sw_code = alaw_to_slinear16_be_mts;
! 429: break;
! 430: }
! 431: if (p->channels == 2) {
! 432: p->factor = 2;
! 433: p->sw_code = alaw_to_slinear16_be;
! 434: break;
! 435: }
! 436: } else
! 437: break; /* XXX */
! 438: return (EINVAL);
! 439:
! 440: default:
! 441: return (EINVAL);
! 442: }
! 443: }
! 444:
! 445: /* Set the speed */
! 446: if (i2s_set_rate(sc, play->sample_rate))
! 447: return EINVAL;
! 448:
! 449: p->sample_rate = sc->sc_rate;
! 450:
! 451: return 0;
! 452: }
! 453:
! 454: int
! 455: i2s_round_blocksize(h, size)
! 456: void *h;
! 457: int size;
! 458: {
! 459: if (size < NBPG)
! 460: size = NBPG;
! 461: return size & ~PGOFSET;
! 462: }
! 463:
! 464: int
! 465: i2s_halt_output(h)
! 466: void *h;
! 467: {
! 468: struct i2s_softc *sc = h;
! 469:
! 470: dbdma_stop(sc->sc_odma);
! 471: dbdma_reset(sc->sc_odma);
! 472: return 0;
! 473: }
! 474:
! 475: int
! 476: i2s_halt_input(h)
! 477: void *h;
! 478: {
! 479: struct i2s_softc *sc = h;
! 480:
! 481: dbdma_stop(sc->sc_idma);
! 482: dbdma_reset(sc->sc_idma);
! 483: return 0;
! 484: }
! 485:
! 486: enum {
! 487: I2S_OUTPUT_CLASS,
! 488: I2S_RECORD_CLASS,
! 489: I2S_OUTPUT_SELECT,
! 490: I2S_VOL_OUTPUT,
! 491: I2S_INPUT_SELECT,
! 492: I2S_VOL_INPUT,
! 493: I2S_BASS,
! 494: I2S_TREBLE,
! 495: I2S_ENUM_LAST
! 496: };
! 497:
! 498: int
! 499: i2s_set_port(h, mc)
! 500: void *h;
! 501: mixer_ctrl_t *mc;
! 502: {
! 503: struct i2s_softc *sc = h;
! 504: int l, r;
! 505:
! 506: DPRINTF(("i2s_set_port dev = %d, type = %d\n", mc->dev, mc->type));
! 507:
! 508: l = mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT];
! 509: r = mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT];
! 510:
! 511: switch (mc->dev) {
! 512: case I2S_OUTPUT_SELECT:
! 513: /* No change necessary? */
! 514: if (mc->un.mask == sc->sc_output_mask)
! 515: return 0;
! 516:
! 517: i2s_mute_speaker(sc, 1);
! 518: i2s_mute_headphone(sc, 1);
! 519: i2s_mute_lineout(sc, 1);
! 520: if (mc->un.mask & 1 << 0)
! 521: i2s_mute_speaker(sc, 0);
! 522: if (mc->un.mask & 1 << 1)
! 523: i2s_mute_headphone(sc, 0);
! 524: if (mc->un.mask & 1 << 2)
! 525: i2s_mute_lineout(sc, 0);
! 526:
! 527: sc->sc_output_mask = mc->un.mask;
! 528: return 0;
! 529:
! 530: case I2S_VOL_OUTPUT:
! 531: (*sc->sc_setvolume)(sc, l, r);
! 532: return 0;
! 533:
! 534: case I2S_BASS:
! 535: if (sc->sc_setbass != NULL)
! 536: (*sc->sc_setbass)(sc, l);
! 537: return (0);
! 538:
! 539: case I2S_TREBLE:
! 540: if (sc->sc_settreble != NULL)
! 541: (*sc->sc_settreble)(sc, l);
! 542: return (0);
! 543:
! 544: case I2S_INPUT_SELECT:
! 545: /* no change necessary? */
! 546: if (mc->un.mask == sc->sc_record_source)
! 547: return 0;
! 548: switch (mc->un.mask) {
! 549: case 1 << 0: /* CD */
! 550: case 1 << 1: /* microphone */
! 551: case 1 << 2: /* line in */
! 552: /* XXX TO BE DONE */
! 553: break;
! 554: default: /* invalid argument */
! 555: return EINVAL;
! 556: }
! 557: sc->sc_record_source = mc->un.mask;
! 558: return 0;
! 559:
! 560: case I2S_VOL_INPUT:
! 561: /* XXX TO BE DONE */
! 562: return 0;
! 563: }
! 564:
! 565: return ENXIO;
! 566: }
! 567:
! 568: int
! 569: i2s_get_port(h, mc)
! 570: void *h;
! 571: mixer_ctrl_t *mc;
! 572: {
! 573: struct i2s_softc *sc = h;
! 574:
! 575: DPRINTF(("i2s_get_port dev = %d, type = %d\n", mc->dev, mc->type));
! 576:
! 577: switch (mc->dev) {
! 578: case I2S_OUTPUT_SELECT:
! 579: mc->un.mask = sc->sc_output_mask;
! 580: return 0;
! 581:
! 582: case I2S_VOL_OUTPUT:
! 583: mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = sc->sc_vol_l;
! 584: mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = sc->sc_vol_r;
! 585: return 0;
! 586:
! 587: case I2S_INPUT_SELECT:
! 588: mc->un.mask = sc->sc_record_source;
! 589: return 0;
! 590:
! 591: case I2S_BASS:
! 592: mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_bass;
! 593: return (0);
! 594:
! 595: case I2S_TREBLE:
! 596: mc->un.value.level[AUDIO_MIXER_LEVEL_MONO] = sc->sc_treble;
! 597: return (0);
! 598:
! 599: case I2S_VOL_INPUT:
! 600: /* XXX TO BE DONE */
! 601: mc->un.value.level[AUDIO_MIXER_LEVEL_LEFT] = 0;
! 602: mc->un.value.level[AUDIO_MIXER_LEVEL_RIGHT] = 0;
! 603: return 0;
! 604:
! 605: default:
! 606: return ENXIO;
! 607: }
! 608:
! 609: return 0;
! 610: }
! 611:
! 612: int
! 613: i2s_query_devinfo(h, dip)
! 614: void *h;
! 615: mixer_devinfo_t *dip;
! 616: {
! 617: struct i2s_softc *sc = h;
! 618: int n = 0;
! 619:
! 620: switch (dip->index) {
! 621:
! 622: case I2S_OUTPUT_SELECT:
! 623: dip->mixer_class = I2S_OUTPUT_CLASS;
! 624: strlcpy(dip->label.name, AudioNselect, sizeof(dip->label.name));
! 625: dip->type = AUDIO_MIXER_SET;
! 626: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 627: strlcpy(dip->un.s.member[n].label.name, AudioNspeaker,
! 628: sizeof(dip->un.s.member[n].label.name));
! 629: dip->un.s.member[n++].mask = 1 << 0;
! 630: if (headphone_mute) {
! 631: strlcpy(dip->un.s.member[n].label.name,
! 632: AudioNheadphone,
! 633: sizeof(dip->un.s.member[n].label.name));
! 634: dip->un.s.member[n++].mask = 1 << 1;
! 635: }
! 636: if (lineout_mute) {
! 637: strlcpy(dip->un.s.member[n].label.name, AudioNline,
! 638: sizeof(dip->un.s.member[n].label.name));
! 639: dip->un.s.member[n++].mask = 1 << 2;
! 640: }
! 641: dip->un.s.num_mem = n;
! 642: return 0;
! 643:
! 644: case I2S_VOL_OUTPUT:
! 645: dip->mixer_class = I2S_OUTPUT_CLASS;
! 646: strlcpy(dip->label.name, AudioNmaster, sizeof(dip->label.name));
! 647: dip->type = AUDIO_MIXER_VALUE;
! 648: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 649: dip->un.v.num_channels = 2;
! 650: strlcpy(dip->un.v.units.name, AudioNvolume,
! 651: sizeof(dip->un.v.units.name));
! 652: return 0;
! 653:
! 654: case I2S_INPUT_SELECT:
! 655: dip->mixer_class = I2S_RECORD_CLASS;
! 656: strlcpy(dip->label.name, AudioNsource, sizeof(dip->label.name));
! 657: dip->type = AUDIO_MIXER_SET;
! 658: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 659: dip->un.s.num_mem = 3;
! 660: strlcpy(dip->un.s.member[0].label.name, AudioNcd,
! 661: sizeof(dip->un.s.member[0].label.name));
! 662: dip->un.s.member[0].mask = 1 << 0;
! 663: strlcpy(dip->un.s.member[1].label.name, AudioNmicrophone,
! 664: sizeof(dip->un.s.member[1].label.name));
! 665: dip->un.s.member[1].mask = 1 << 1;
! 666: strlcpy(dip->un.s.member[2].label.name, AudioNline,
! 667: sizeof(dip->un.s.member[2].label.name));
! 668: dip->un.s.member[2].mask = 1 << 2;
! 669: return 0;
! 670:
! 671: case I2S_VOL_INPUT:
! 672: dip->mixer_class = I2S_RECORD_CLASS;
! 673: strlcpy(dip->label.name, AudioNrecord, sizeof(dip->label.name));
! 674: dip->type = AUDIO_MIXER_VALUE;
! 675: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 676: dip->un.v.num_channels = 2;
! 677: strlcpy(dip->un.v.units.name, AudioNvolume,
! 678: sizeof(dip->un.v.units.name));
! 679: return 0;
! 680:
! 681: case I2S_OUTPUT_CLASS:
! 682: dip->mixer_class = I2S_OUTPUT_CLASS;
! 683: strlcpy(dip->label.name, AudioCoutputs,
! 684: sizeof(dip->label.name));
! 685: dip->type = AUDIO_MIXER_CLASS;
! 686: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 687: return 0;
! 688:
! 689: case I2S_RECORD_CLASS:
! 690: dip->mixer_class = I2S_RECORD_CLASS;
! 691: strlcpy(dip->label.name, AudioCrecord, sizeof(dip->label.name));
! 692: dip->type = AUDIO_MIXER_CLASS;
! 693: dip->next = dip->prev = AUDIO_MIXER_LAST;
! 694: return 0;
! 695:
! 696: case I2S_BASS:
! 697: if (sc->sc_setbass == NULL)
! 698: return (ENXIO);
! 699: dip->mixer_class = I2S_OUTPUT_CLASS;
! 700: strlcpy(dip->label.name, AudioNbass, sizeof(dip->label.name));
! 701: dip->type = AUDIO_MIXER_VALUE;
! 702: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 703: dip->un.v.num_channels = 1;
! 704: return (0);
! 705:
! 706: case I2S_TREBLE:
! 707: if (sc->sc_settreble == NULL)
! 708: return (ENXIO);
! 709: dip->mixer_class = I2S_OUTPUT_CLASS;
! 710: strlcpy(dip->label.name, AudioNtreble, sizeof(dip->label.name));
! 711: dip->type = AUDIO_MIXER_VALUE;
! 712: dip->prev = dip->next = AUDIO_MIXER_LAST;
! 713: dip->un.v.num_channels = 1;
! 714: return (0);
! 715: }
! 716:
! 717: return ENXIO;
! 718: }
! 719:
! 720: size_t
! 721: i2s_round_buffersize(h, dir, size)
! 722: void *h;
! 723: int dir;
! 724: size_t size;
! 725: {
! 726: if (size > 65536)
! 727: size = 65536;
! 728: return size;
! 729: }
! 730:
! 731: paddr_t
! 732: i2s_mappage(h, mem, off, prot)
! 733: void *h;
! 734: void *mem;
! 735: off_t off;
! 736: int prot;
! 737: {
! 738: if (off < 0)
! 739: return -1;
! 740: return -1; /* XXX */
! 741: }
! 742:
! 743: int
! 744: i2s_get_props(h)
! 745: void *h;
! 746: {
! 747: return AUDIO_PROP_FULLDUPLEX /* | AUDIO_PROP_MMAP */;
! 748: }
! 749:
! 750: int
! 751: i2s_trigger_output(h, start, end, bsize, intr, arg, param)
! 752: void *h;
! 753: void *start, *end;
! 754: int bsize;
! 755: void (*intr)(void *);
! 756: void *arg;
! 757: struct audio_params *param;
! 758: {
! 759: struct i2s_softc *sc = h;
! 760: struct i2s_dma *p;
! 761: struct dbdma_command *cmd = sc->sc_odmacmd;
! 762: vaddr_t spa, pa, epa;
! 763: int c;
! 764:
! 765: DPRINTF(("trigger_output %p %p 0x%x\n", start, end, bsize));
! 766:
! 767: for (p = sc->sc_dmas; p && p->addr != start; p = p->next);
! 768: if (!p)
! 769: return -1;
! 770:
! 771: sc->sc_ointr = intr;
! 772: sc->sc_oarg = arg;
! 773: sc->sc_odmap = sc->sc_odmacmd;
! 774:
! 775: spa = p->segs[0].ds_addr;
! 776: c = DBDMA_CMD_OUT_MORE;
! 777: for (pa = spa, epa = spa + (end - start);
! 778: pa < epa; pa += bsize, cmd++) {
! 779:
! 780: if (pa + bsize == epa)
! 781: c = DBDMA_CMD_OUT_LAST;
! 782:
! 783: DBDMA_BUILD(cmd, c, 0, bsize, pa, DBDMA_INT_ALWAYS,
! 784: DBDMA_WAIT_NEVER, DBDMA_BRANCH_NEVER);
! 785: }
! 786:
! 787: DBDMA_BUILD(cmd, DBDMA_CMD_NOP, 0, 0, 0,
! 788: DBDMA_INT_NEVER, DBDMA_WAIT_NEVER, DBDMA_BRANCH_ALWAYS);
! 789: dbdma_st32(&cmd->d_cmddep, sc->sc_odbdma->d_paddr);
! 790:
! 791: dbdma_start(sc->sc_odma, sc->sc_odbdma);
! 792:
! 793: return 0;
! 794: }
! 795:
! 796: int
! 797: i2s_trigger_input(h, start, end, bsize, intr, arg, param)
! 798: void *h;
! 799: void *start, *end;
! 800: int bsize;
! 801: void (*intr)(void *);
! 802: void *arg;
! 803: struct audio_params *param;
! 804: {
! 805: DPRINTF(("i2s_trigger_input called\n"));
! 806:
! 807: return 1;
! 808: }
! 809:
! 810:
! 811: /* rate = fs = LRCLK
! 812: * SCLK = 64*LRCLK (I2S)
! 813: * MCLK = 256fs (typ. -- changeable)
! 814: * MCLK = clksrc / mdiv
! 815: * SCLK = MCLK / sdiv
! 816: * rate = SCLK / 64 ( = LRCLK = fs)
! 817: */
! 818: int
! 819: i2s_set_rate(sc, rate)
! 820: struct i2s_softc *sc;
! 821: int rate;
! 822: {
! 823: u_int reg = 0;
! 824: int MCLK;
! 825: int clksrc, mdiv, sdiv;
! 826: int mclk_fs;
! 827: int timo;
! 828:
! 829: /* sanify */
! 830: if (rate > 48000)
! 831: rate = 48000;
! 832: else if (rate < 8000)
! 833: rate = 8000;
! 834:
! 835: switch (rate) {
! 836: case 8000:
! 837: clksrc = 18432000; /* 18MHz */
! 838: reg = CLKSRC_18MHz;
! 839: mclk_fs = 256;
! 840: break;
! 841:
! 842: case 44100:
! 843: clksrc = 45158400; /* 45MHz */
! 844: reg = CLKSRC_45MHz;
! 845: mclk_fs = 256;
! 846: break;
! 847:
! 848: case 48000:
! 849: clksrc = 49152000; /* 49MHz */
! 850: reg = CLKSRC_49MHz;
! 851: mclk_fs = 256;
! 852: break;
! 853:
! 854: default:
! 855: return EINVAL;
! 856: }
! 857:
! 858: MCLK = rate * mclk_fs;
! 859: mdiv = clksrc / MCLK; /* 4 */
! 860: sdiv = mclk_fs / 64; /* 4 */
! 861:
! 862: switch (mdiv) {
! 863: case 1:
! 864: reg |= MCLK_DIV1;
! 865: break;
! 866: case 3:
! 867: reg |= MCLK_DIV3;
! 868: break;
! 869: case 5:
! 870: reg |= MCLK_DIV5;
! 871: break;
! 872: default:
! 873: reg |= ((mdiv / 2 - 1) << 24) & 0x1f000000;
! 874: break;
! 875: }
! 876:
! 877: switch (sdiv) {
! 878: case 1:
! 879: reg |= SCLK_DIV1;
! 880: break;
! 881: case 3:
! 882: reg |= SCLK_DIV3;
! 883: break;
! 884: default:
! 885: reg |= ((sdiv / 2 - 1) << 20) & 0x00f00000;
! 886: break;
! 887: }
! 888:
! 889: reg |= SCLK_MASTER; /* XXX master mode */
! 890:
! 891: reg |= SERIAL_64x;
! 892:
! 893: if (sc->sc_rate == rate)
! 894: return (0);
! 895:
! 896: /* stereo input and output */
! 897: DPRINTF(("I2SSetDataWordSizeReg 0x%08x -> 0x%08x\n",
! 898: in32rb(sc->sc_reg + I2S_WORDSIZE), 0x02000200));
! 899: out32rb(sc->sc_reg + I2S_WORDSIZE, 0x02000200);
! 900:
! 901: /* Clear CLKSTOPPEND */
! 902: out32rb(sc->sc_reg + I2S_INT, I2S_INT_CLKSTOPPEND);
! 903:
! 904: keylargo_fcr_disable(I2SClockOffset, I2S0CLKEN);
! 905:
! 906: /* Wait until clock is stopped */
! 907: for (timo = 1000; timo > 0; timo--) {
! 908: if (in32rb(sc->sc_reg + I2S_INT) & I2S_INT_CLKSTOPPEND)
! 909: goto done;
! 910: delay(1);
! 911: }
! 912:
! 913: printf("i2s_set_rate: timeout\n");
! 914:
! 915: done:
! 916: DPRINTF(("I2SSetSerialFormatReg 0x%x -> 0x%x\n",
! 917: in32rb(sc->sc_reg + I2S_FORMAT), reg));
! 918: out32rb(sc->sc_reg + I2S_FORMAT, reg);
! 919:
! 920: keylargo_fcr_enable(I2SClockOffset, I2S0CLKEN);
! 921:
! 922: sc->sc_rate = rate;
! 923:
! 924: return 0;
! 925: }
! 926:
! 927: int
! 928: gpio_read(addr)
! 929: char *addr;
! 930: {
! 931: if (*addr & GPIO_DATA)
! 932: return 1;
! 933: return 0;
! 934: }
! 935:
! 936: void
! 937: gpio_write(addr, val)
! 938: char *addr;
! 939: int val;
! 940: {
! 941: u_int data = GPIO_DDR_OUTPUT;
! 942:
! 943: if (val)
! 944: data |= GPIO_DATA;
! 945: *addr = data;
! 946: asm volatile ("eieio" ::: "memory");
! 947: }
! 948:
! 949: #define amp_active 0 /* XXX OF */
! 950: #define headphone_active 0 /* XXX OF */
! 951: #define lineout_active 0 /* XXX OF */
! 952:
! 953: void
! 954: i2s_mute_speaker(sc, mute)
! 955: struct i2s_softc *sc;
! 956: int mute;
! 957: {
! 958: u_int x;
! 959:
! 960: if (amp_mute == NULL)
! 961: return;
! 962:
! 963: DPRINTF(("ampmute %d --> ", gpio_read(amp_mute)));
! 964:
! 965: if (mute)
! 966: x = amp_active; /* mute */
! 967: else
! 968: x = !amp_active; /* unmute */
! 969: if (x != gpio_read(amp_mute))
! 970: gpio_write(amp_mute, x);
! 971:
! 972: DPRINTF(("%d\n", gpio_read(amp_mute)));
! 973: }
! 974:
! 975: void
! 976: i2s_mute_headphone(sc, mute)
! 977: struct i2s_softc *sc;
! 978: int mute;
! 979: {
! 980: u_int x;
! 981:
! 982: if (headphone_mute == NULL)
! 983: return;
! 984:
! 985: DPRINTF(("headphonemute %d --> ", gpio_read(headphone_mute)));
! 986:
! 987: if (mute)
! 988: x = headphone_active; /* mute */
! 989: else
! 990: x = !headphone_active; /* unmute */
! 991: if (x != gpio_read(headphone_mute))
! 992: gpio_write(headphone_mute, x);
! 993:
! 994: DPRINTF(("%d\n", gpio_read(headphone_mute)));
! 995: }
! 996:
! 997: void
! 998: i2s_mute_lineout(sc, mute)
! 999: struct i2s_softc *sc;
! 1000: int mute;
! 1001: {
! 1002: u_int x;
! 1003:
! 1004: if (lineout_mute == NULL)
! 1005: return;
! 1006:
! 1007: DPRINTF(("lineout %d --> ", gpio_read(lineout_mute)));
! 1008:
! 1009: if (mute)
! 1010: x = lineout_active; /* mute */
! 1011: else
! 1012: x = !lineout_active; /* unmute */
! 1013: if (x != gpio_read(lineout_mute))
! 1014: gpio_write(lineout_mute, x);
! 1015:
! 1016: DPRINTF(("%d\n", gpio_read(lineout_mute)));
! 1017: }
! 1018:
! 1019: int
! 1020: i2s_cint(v)
! 1021: void *v;
! 1022: {
! 1023: struct i2s_softc *sc = v;
! 1024: u_int sense;
! 1025:
! 1026: sc->sc_output_mask = 0;
! 1027: i2s_mute_speaker(sc, 1);
! 1028: i2s_mute_headphone(sc, 1);
! 1029: i2s_mute_lineout(sc, 1);
! 1030:
! 1031: if (headphone_detect)
! 1032: sense = *headphone_detect;
! 1033: else
! 1034: sense = !headphone_detect_active << 1;
! 1035: DPRINTF(("headphone detect = 0x%x\n", sense));
! 1036:
! 1037: if (((sense & 0x02) >> 1) == headphone_detect_active) {
! 1038: DPRINTF(("headphone is inserted\n"));
! 1039: sc->sc_output_mask |= 1 << 1;
! 1040: i2s_mute_headphone(sc, 0);
! 1041: } else {
! 1042: DPRINTF(("headphone is NOT inserted\n"));
! 1043: }
! 1044:
! 1045: if (lineout_detect)
! 1046: sense = *lineout_detect;
! 1047: else
! 1048: sense = !lineout_detect_active << 1;
! 1049: DPRINTF(("lineout detect = 0x%x\n", sense));
! 1050:
! 1051: if (((sense & 0x02) >> 1) == lineout_detect_active) {
! 1052: DPRINTF(("lineout is inserted\n"));
! 1053: sc->sc_output_mask |= 1 << 2;
! 1054: i2s_mute_lineout(sc, 0);
! 1055: } else {
! 1056: DPRINTF(("lineout is NOT inserted\n"));
! 1057: }
! 1058:
! 1059: if (sc->sc_output_mask == 0) {
! 1060: sc->sc_output_mask |= 1 << 0;
! 1061: i2s_mute_speaker(sc, 0);
! 1062: }
! 1063:
! 1064: return 1;
! 1065: }
! 1066:
! 1067: u_char *
! 1068: i2s_gpio_map(struct i2s_softc *sc, char *name, int *irq)
! 1069: {
! 1070: u_int32_t reg[2];
! 1071: u_int32_t intr[2];
! 1072: int gpio;
! 1073:
! 1074: if (OF_getprop(sc->sc_node, name, &gpio,
! 1075: sizeof(gpio)) != sizeof(gpio) ||
! 1076: OF_getprop(gpio, "reg", ®[0],
! 1077: sizeof(reg[0])) != sizeof(reg[0]) ||
! 1078: OF_getprop(OF_parent(gpio), "reg", ®[1],
! 1079: sizeof(reg[1])) != sizeof(reg[1]))
! 1080: return NULL;
! 1081:
! 1082: if (irq && OF_getprop(gpio, "interrupts",
! 1083: intr, sizeof(intr)) == sizeof(intr)) {
! 1084: *irq = intr[0];
! 1085: }
! 1086:
! 1087: return mapiodev(sc->sc_baseaddr + reg[0] + reg[1], 1);
! 1088: }
! 1089:
! 1090: void
! 1091: i2s_gpio_init(sc, node, parent)
! 1092: struct i2s_softc *sc;
! 1093: int node;
! 1094: struct device *parent;
! 1095: {
! 1096: int gpio;
! 1097: int headphone_detect_intr = -1, headphone_detect_intrtype;
! 1098: int lineout_detect_intr = -1;
! 1099:
! 1100: /* Map gpios. */
! 1101: amp_mute = i2s_gpio_map(sc, "platform-amp-mute", NULL);
! 1102: headphone_mute = i2s_gpio_map(sc, "platform-headphone-mute", NULL);
! 1103: headphone_detect = i2s_gpio_map(sc, "platform-headphone-detect",
! 1104: &headphone_detect_intr);
! 1105: lineout_mute = i2s_gpio_map(sc, "platform-lineout-mute", NULL);
! 1106: lineout_detect = i2s_gpio_map(sc, "platform-lineout-detect",
! 1107: &lineout_detect_intr);
! 1108: audio_hw_reset = i2s_gpio_map(sc, "platform-hw-reset", NULL);
! 1109:
! 1110: gpio = OF_getnodebyname(OF_parent(node), "gpio");
! 1111: DPRINTF((" /gpio 0x%x\n", gpio));
! 1112: gpio = OF_child(gpio);
! 1113: while (gpio) {
! 1114: char name[64], audio_gpio[64];
! 1115: int intr[2];
! 1116: paddr_t addr;
! 1117:
! 1118: bzero(name, sizeof name);
! 1119: bzero(audio_gpio, sizeof audio_gpio);
! 1120: addr = 0;
! 1121: OF_getprop(gpio, "name", name, sizeof name);
! 1122: OF_getprop(gpio, "audio-gpio", audio_gpio, sizeof audio_gpio);
! 1123: OF_getprop(gpio, "AAPL,address", &addr, sizeof addr);
! 1124: /* printf("0x%x %s %s\n", gpio, name, audio_gpio); */
! 1125:
! 1126: /* gpio5 */
! 1127: if (headphone_mute == NULL &&
! 1128: strcmp(audio_gpio, "headphone-mute") == 0)
! 1129: headphone_mute = mapiodev(addr,1);
! 1130:
! 1131: /* gpio6 */
! 1132: if (amp_mute == NULL &&
! 1133: strcmp(audio_gpio, "amp-mute") == 0)
! 1134: amp_mute = mapiodev(addr,1);
! 1135:
! 1136: /* extint-gpio15 */
! 1137: if (headphone_detect == NULL &&
! 1138: strcmp(audio_gpio, "headphone-detect") == 0) {
! 1139: headphone_detect = mapiodev(addr,1);
! 1140: OF_getprop(gpio, "audio-gpio-active-state",
! 1141: &headphone_detect_active, 4);
! 1142: OF_getprop(gpio, "interrupts", intr, 8);
! 1143: headphone_detect_intr = intr[0];
! 1144: headphone_detect_intrtype = intr[1];
! 1145: }
! 1146:
! 1147: /* gpio11 (keywest-11) */
! 1148: if (audio_hw_reset == NULL &&
! 1149: strcmp(audio_gpio, "audio-hw-reset") == 0)
! 1150: audio_hw_reset = mapiodev(addr,1);
! 1151:
! 1152: gpio = OF_peer(gpio);
! 1153: }
! 1154: DPRINTF((" amp-mute %p\n", amp_mute));
! 1155: DPRINTF((" headphone-mute %p\n", headphone_mute));
! 1156: DPRINTF((" headphone-detect %p\n", headphone_detect));
! 1157: DPRINTF((" headphone-detect active %x\n", headphone_detect_active));
! 1158: DPRINTF((" headphone-detect intr %x\n", headphone_detect_intr));
! 1159: DPRINTF((" lineout-mute %p\n", lineout_mute));
! 1160: DPRINTF((" lineout-detect %p\n", lineout_detect));
! 1161: DPRINTF((" lineout-detect active %x\n", lineout_detect_active));
! 1162: DPRINTF((" lineout-detect intr %x\n", lineout_detect_intr));
! 1163: DPRINTF((" audio-hw-reset %p\n", audio_hw_reset));
! 1164:
! 1165: if (headphone_detect_intr != -1)
! 1166: mac_intr_establish(parent, headphone_detect_intr, IST_EDGE,
! 1167: IPL_AUDIO, i2s_cint, sc, sc->sc_dev.dv_xname);
! 1168:
! 1169: if (lineout_detect_intr != -1)
! 1170: mac_intr_establish(parent, lineout_detect_intr, IST_EDGE,
! 1171: IPL_AUDIO, i2s_cint, sc, sc->sc_dev.dv_xname);
! 1172:
! 1173: /* Enable headphone interrupt? */
! 1174: *headphone_detect |= 0x80;
! 1175: asm volatile("eieio");
! 1176:
! 1177: /* Update headphone status. */
! 1178: i2s_cint(sc);
! 1179: }
! 1180:
! 1181: void *
! 1182: i2s_allocm(void *h, int dir, size_t size, int type, int flags)
! 1183: {
! 1184: struct i2s_softc *sc = h;
! 1185: struct i2s_dma *p;
! 1186: int error;
! 1187:
! 1188: if (size > I2S_DMALIST_MAX * I2S_DMASEG_MAX)
! 1189: return (NULL);
! 1190:
! 1191: p = malloc(sizeof(*p), type, flags);
! 1192: if (!p)
! 1193: return (NULL);
! 1194: bzero(p, sizeof(*p));
! 1195:
! 1196: /* convert to the bus.h style, not used otherwise */
! 1197: if (flags & M_NOWAIT)
! 1198: flags = BUS_DMA_NOWAIT;
! 1199:
! 1200: p->size = size;
! 1201: if ((error = bus_dmamem_alloc(sc->sc_dmat, p->size, NBPG, 0, p->segs,
! 1202: 1, &p->nsegs, flags)) != 0) {
! 1203: printf("%s: unable to allocate dma, error = %d\n",
! 1204: sc->sc_dev.dv_xname, error);
! 1205: free(p, type);
! 1206: return NULL;
! 1207: }
! 1208:
! 1209: if ((error = bus_dmamem_map(sc->sc_dmat, p->segs, p->nsegs, p->size,
! 1210: &p->addr, flags | BUS_DMA_COHERENT)) != 0) {
! 1211: printf("%s: unable to map dma, error = %d\n",
! 1212: sc->sc_dev.dv_xname, error);
! 1213: bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
! 1214: free(p, type);
! 1215: return NULL;
! 1216: }
! 1217:
! 1218: if ((error = bus_dmamap_create(sc->sc_dmat, p->size, 1,
! 1219: p->size, 0, flags, &p->map)) != 0) {
! 1220: printf("%s: unable to create dma map, error = %d\n",
! 1221: sc->sc_dev.dv_xname, error);
! 1222: bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
! 1223: bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
! 1224: free(p, type);
! 1225: return NULL;
! 1226: }
! 1227:
! 1228: if ((error = bus_dmamap_load(sc->sc_dmat, p->map, p->addr, p->size,
! 1229: NULL, flags)) != 0) {
! 1230: printf("%s: unable to load dma map, error = %d\n",
! 1231: sc->sc_dev.dv_xname, error);
! 1232: bus_dmamap_destroy(sc->sc_dmat, p->map);
! 1233: bus_dmamem_unmap(sc->sc_dmat, p->addr, size);
! 1234: bus_dmamem_free(sc->sc_dmat, p->segs, p->nsegs);
! 1235: free(p, type);
! 1236: return NULL;
! 1237: }
! 1238:
! 1239: p->next = sc->sc_dmas;
! 1240: sc->sc_dmas = p;
! 1241:
! 1242: return p->addr;
! 1243: }
! 1244:
! 1245: #define reset_active 0
! 1246:
! 1247: int
! 1248: deq_reset(struct i2s_softc *sc)
! 1249: {
! 1250: if (audio_hw_reset == NULL)
! 1251: return (-1);
! 1252:
! 1253: gpio_write(audio_hw_reset, !reset_active);
! 1254: delay(1000000);
! 1255:
! 1256: gpio_write(audio_hw_reset, reset_active);
! 1257: delay(1);
! 1258:
! 1259: gpio_write(audio_hw_reset, !reset_active);
! 1260: delay(10000);
! 1261:
! 1262: return (0);
! 1263: }
CVSweb