[BACK]Return to i2s.c CVS log [TXT][DIR] Up to [local] / sys / arch / macppc / dev

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", &reg[0],
        !          1077:            sizeof(reg[0])) != sizeof(reg[0]) ||
        !          1078:            OF_getprop(OF_parent(gpio), "reg", &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