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

Annotation of sys/arch/macppc/dev/kiic.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: kiic.c,v 1.2 2007/05/20 23:38:52 thib Exp $   */
        !             2: /*     $NetBSD: kiic.c,v 1.1 2003/12/27 02:19:34 grant Exp $   */
        !             3:
        !             4: /*-
        !             5:  * Copyright (c) 2001 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/device.h>
        !            32: #include <sys/systm.h>
        !            33:
        !            34: #include <dev/ofw/openfirm.h>
        !            35: #include <uvm/uvm_extern.h>
        !            36: #include <machine/autoconf.h>
        !            37:
        !            38: #include <macppc/dev/kiicvar.h>
        !            39: #include <macppc/dev/maci2cvar.h>
        !            40:
        !            41: int kiic_match(struct device *, void *, void *);
        !            42: void kiic_attach(struct device *, struct device *, void *);
        !            43: void kiic_attach_bus(struct kiic_softc *, struct kiic_bus *, int);
        !            44: inline u_int kiic_readreg(struct kiic_softc *, int);
        !            45: inline void kiic_writereg(struct kiic_softc *, int, u_int);
        !            46: u_int kiic_getmode(struct kiic_softc *);
        !            47: void kiic_setmode(struct kiic_softc *, u_int, u_int);
        !            48: u_int kiic_getspeed(struct kiic_softc *);
        !            49: void kiic_setspeed(struct kiic_softc *, u_int);
        !            50: int kiic_intr(struct kiic_softc *);
        !            51: int kiic_poll(struct kiic_softc *, int);
        !            52: int kiic_start(struct kiic_softc *, int, int, void *, int);
        !            53: int kiic_read(struct kiic_softc *, int, int, void *, int);
        !            54: int kiic_write(struct kiic_softc *, int, int, const void *, int);
        !            55:
        !            56: /* I2C glue */
        !            57: int kiic_i2c_acquire_bus(void *, int);
        !            58: void kiic_i2c_release_bus(void *, int);
        !            59: int kiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *, size_t,
        !            60:     void *, size_t, int);
        !            61:
        !            62: struct cfattach kiic_ca = {
        !            63:        sizeof(struct kiic_softc), kiic_match, kiic_attach
        !            64: };
        !            65: struct cfattach kiic_memc_ca = {
        !            66:        sizeof(struct kiic_softc), kiic_match, kiic_attach
        !            67: };
        !            68:
        !            69: struct cfdriver kiic_cd = {
        !            70:        NULL, "kiic", DV_DULL
        !            71: };
        !            72:
        !            73: int
        !            74: kiic_match(struct device *parent, void *match, void *aux)
        !            75: {
        !            76:        struct confargs *ca = aux;
        !            77:
        !            78:        if (strcmp(ca->ca_name, "i2c") == 0 &&
        !            79:           ca->ca_nreg >= 4)
        !            80:                return (1);
        !            81:
        !            82:        return (0);
        !            83: }
        !            84:
        !            85: void
        !            86: kiic_attach(struct device *parent, struct device *self, void *aux)
        !            87: {
        !            88:        struct kiic_softc *sc = (struct kiic_softc *)self;
        !            89:        struct confargs *ca = aux;
        !            90:        int node = ca->ca_node;
        !            91:        int rate, count = 0;
        !            92:        char name[32];
        !            93:
        !            94:        ca->ca_reg[0] += ca->ca_baseaddr;
        !            95:
        !            96:        if (OF_getprop(node, "AAPL,i2c-rate", &rate, 4) != 4) {
        !            97:                printf(": cannot get i2c-rate\n");
        !            98:                return;
        !            99:        }
        !           100:        if (OF_getprop(node, "AAPL,address", &sc->sc_paddr, 4) != 4) {
        !           101:                printf(": unable to find i2c address\n");
        !           102:                return;
        !           103:        }
        !           104:        if (OF_getprop(node, "AAPL,address-step", &sc->sc_regstep, 4) != 4) {
        !           105:                printf(": unable to find i2c address step\n");
        !           106:                return;
        !           107:        }
        !           108:        sc->sc_reg = mapiodev(sc->sc_paddr, (DATA+1)*sc->sc_regstep);
        !           109:
        !           110:        printf("\n");
        !           111:
        !           112:        kiic_writereg(sc, STATUS, 0);
        !           113:        kiic_writereg(sc, ISR, 0);
        !           114:        kiic_writereg(sc, IER, 0);
        !           115:
        !           116:        kiic_setmode(sc, I2C_STDSUBMODE, 0);
        !           117:        kiic_setspeed(sc, I2C_100kHz);          /* XXX rate */
        !           118:
        !           119:        rw_init(&sc->sc_buslock, sc->sc_dev.dv_xname);
        !           120:        kiic_writereg(sc, IER,I2C_INT_DATA|I2C_INT_ADDR|I2C_INT_STOP);
        !           121:
        !           122:        for (node = OF_child(ca->ca_node); node; node = OF_peer(node)) {
        !           123:                if (OF_getprop(node, "name", &name, sizeof name) > 0) {
        !           124:                        if (strcmp(name, "i2c-bus") == 0) {
        !           125:                                kiic_attach_bus(sc, &sc->sc_bus[count], node);
        !           126:                                if (++count >= KIIC_MAX_BUSSES)
        !           127:                                        break;
        !           128:                        }
        !           129:                }
        !           130:        }
        !           131:
        !           132:        /*
        !           133:         * If we didn't find any i2c-bus nodes, there is only a single
        !           134:         * i2c bus.
        !           135:         */
        !           136:
        !           137:        if (count == 0)
        !           138:                kiic_attach_bus(sc, &sc->sc_bus[0], ca->ca_node);
        !           139: }
        !           140:
        !           141: void
        !           142: kiic_attach_bus(struct kiic_softc *sc, struct kiic_bus *bus, int node)
        !           143: {
        !           144:        struct i2cbus_attach_args iba;
        !           145:        u_int32_t reg;
        !           146:
        !           147:        if (OF_getprop(node, "reg", &reg, sizeof reg) != sizeof reg)
        !           148:                return;
        !           149:
        !           150:        bus->sc = sc;
        !           151:        bus->i2c_tag.ic_cookie = bus;
        !           152:        bus->i2c_tag.ic_acquire_bus = kiic_i2c_acquire_bus;
        !           153:        bus->i2c_tag.ic_release_bus = kiic_i2c_release_bus;
        !           154:        bus->i2c_tag.ic_exec = kiic_i2c_exec;
        !           155:        bus->reg = reg;
        !           156:
        !           157:        bzero(&iba, sizeof iba);
        !           158:        iba.iba_name = "iic";
        !           159:        iba.iba_tag = &bus->i2c_tag;
        !           160:        iba.iba_bus_scan = maciic_scan;
        !           161:        iba.iba_bus_scan_arg = &node;
        !           162:        config_found(&sc->sc_dev, &iba, NULL);
        !           163: }
        !           164:
        !           165: u_int
        !           166: kiic_readreg(struct kiic_softc *sc, int reg)
        !           167: {
        !           168:        u_char *addr = sc->sc_reg + sc->sc_regstep * reg;
        !           169:
        !           170:        return (*addr);
        !           171: }
        !           172:
        !           173: void
        !           174: kiic_writereg(struct kiic_softc *sc, int reg, u_int val)
        !           175: {
        !           176:        u_char *addr = sc->sc_reg + sc->sc_regstep * reg;
        !           177:
        !           178:        *addr = val;
        !           179:        asm volatile ("eieio");
        !           180:        delay(10);
        !           181: }
        !           182:
        !           183: u_int
        !           184: kiic_getmode(struct kiic_softc *sc)
        !           185: {
        !           186:        return kiic_readreg(sc, MODE) & I2C_MODE;
        !           187: }
        !           188:
        !           189: void
        !           190: kiic_setmode(struct kiic_softc *sc, u_int mode, u_int bus)
        !           191: {
        !           192:        u_int x;
        !           193:
        !           194:        KASSERT((mode & ~I2C_MODE) == 0);
        !           195:        x = kiic_readreg(sc, MODE);
        !           196:        x &= ~(I2C_MODE);
        !           197:        if (bus)
        !           198:                x |= I2C_BUS1;
        !           199:        else
        !           200:                x &= ~I2C_BUS1;
        !           201:        x |= mode;
        !           202:        kiic_writereg(sc, MODE, x);
        !           203: }
        !           204:
        !           205: u_int
        !           206: kiic_getspeed(struct kiic_softc *sc)
        !           207: {
        !           208:        return kiic_readreg(sc, MODE) & I2C_SPEED;
        !           209: }
        !           210:
        !           211: void
        !           212: kiic_setspeed(struct kiic_softc *sc, u_int speed)
        !           213: {
        !           214:        u_int x;
        !           215:
        !           216:        KASSERT((speed & ~I2C_SPEED) == 0);
        !           217:        x = kiic_readreg(sc, MODE);
        !           218:        x &= ~I2C_SPEED;
        !           219:        x |= speed;
        !           220:        kiic_writereg(sc, MODE, x);
        !           221: }
        !           222:
        !           223: int
        !           224: kiic_intr(struct kiic_softc *sc)
        !           225: {
        !           226:        u_int isr, x;
        !           227:
        !           228:        isr = kiic_readreg(sc, ISR);
        !           229:        if (isr & I2C_INT_ADDR) {
        !           230: #if 0
        !           231:                if ((kiic_readreg(sc, STATUS) & I2C_ST_LASTAAK) == 0) {
        !           232:                        /* No slave responded. */
        !           233:                        sc->sc_flags |= I2C_ERROR;
        !           234:                        goto out;
        !           235:                }
        !           236: #endif
        !           237:
        !           238:                if (sc->sc_flags & I2C_READING) {
        !           239:                        if (sc->sc_resid > 1) {
        !           240:                                x = kiic_readreg(sc, CONTROL);
        !           241:                                x |= I2C_CT_AAK;
        !           242:                                kiic_writereg(sc, CONTROL, x);
        !           243:                        }
        !           244:                } else {
        !           245:                        kiic_writereg(sc, DATA, *sc->sc_data++);
        !           246:                        sc->sc_resid--;
        !           247:                }
        !           248:        }
        !           249:
        !           250:        if (isr & I2C_INT_DATA) {
        !           251:                if (sc->sc_flags & I2C_READING) {
        !           252:                        *sc->sc_data++ = kiic_readreg(sc, DATA);
        !           253:                        sc->sc_resid--;
        !           254:
        !           255:                        if (sc->sc_resid == 0) {        /* Completed */
        !           256:                                kiic_writereg(sc, CONTROL, 0);
        !           257:                                goto out;
        !           258:                        }
        !           259:                } else {
        !           260: #if 0
        !           261:                        if ((kiic_readreg(sc, STATUS) & I2C_ST_LASTAAK) == 0) {
        !           262:                                /* No slave responded. */
        !           263:                                sc->sc_flags |= I2C_ERROR;
        !           264:                                goto out;
        !           265:                        }
        !           266: #endif
        !           267:
        !           268:                        if (sc->sc_resid == 0) {
        !           269:                                x = kiic_readreg(sc, CONTROL) | I2C_CT_STOP;
        !           270:                                kiic_writereg(sc, CONTROL, x);
        !           271:                        } else {
        !           272:                                kiic_writereg(sc, DATA, *sc->sc_data++);
        !           273:                                sc->sc_resid--;
        !           274:                        }
        !           275:                }
        !           276:        }
        !           277:
        !           278: out:
        !           279:        if (isr & I2C_INT_STOP) {
        !           280:                kiic_writereg(sc, CONTROL, 0);
        !           281:                sc->sc_flags &= ~I2C_BUSY;
        !           282:        }
        !           283:
        !           284:        kiic_writereg(sc, ISR, isr);
        !           285:
        !           286:        return (1);
        !           287: }
        !           288:
        !           289: int
        !           290: kiic_poll(struct kiic_softc *sc, int timo)
        !           291: {
        !           292:        while (sc->sc_flags & I2C_BUSY) {
        !           293:                if (kiic_readreg(sc, ISR))
        !           294:                        kiic_intr(sc);
        !           295:                timo -= 100;
        !           296:                if (timo < 0) {
        !           297:                        printf("i2c_poll: timeout\n");
        !           298:                        return (-1);
        !           299:                }
        !           300:                delay(100);
        !           301:        }
        !           302:        return (0);
        !           303: }
        !           304:
        !           305: int
        !           306: kiic_start(struct kiic_softc *sc, int addr, int subaddr, void *data, int len)
        !           307: {
        !           308:        int rw = (sc->sc_flags & I2C_READING) ? 1 : 0;
        !           309:        int timo, x;
        !           310:
        !           311:        KASSERT((addr & 1) == 0);
        !           312:
        !           313:        sc->sc_data = data;
        !           314:        sc->sc_resid = len;
        !           315:        sc->sc_flags |= I2C_BUSY;
        !           316:
        !           317:        timo = 1000 + len * 200;
        !           318:
        !           319:        /* XXX TAS3001 sometimes takes 50ms to finish writing registers. */
        !           320:        /* if (addr == 0x68) */
        !           321:                timo += 100000;
        !           322:
        !           323:        kiic_writereg(sc, ADDR, addr | rw);
        !           324:        kiic_writereg(sc, SUBADDR, subaddr);
        !           325:
        !           326:        x = kiic_readreg(sc, CONTROL) | I2C_CT_ADDR;
        !           327:        kiic_writereg(sc, CONTROL, x);
        !           328:
        !           329:        if (kiic_poll(sc, timo))
        !           330:                return (-1);
        !           331:        if (sc->sc_flags & I2C_ERROR) {
        !           332:                printf("I2C_ERROR\n");
        !           333:                return (-1);
        !           334:        }
        !           335:        return (0);
        !           336: }
        !           337:
        !           338: int
        !           339: kiic_read(struct kiic_softc *sc, int addr, int subaddr, void *data, int len)
        !           340: {
        !           341:        sc->sc_flags = I2C_READING;
        !           342:        return kiic_start(sc, addr, subaddr, data, len);
        !           343: }
        !           344:
        !           345: int
        !           346: kiic_write(struct kiic_softc *sc, int addr, int subaddr, const void *data, int len)
        !           347: {
        !           348:        sc->sc_flags = 0;
        !           349:        return kiic_start(sc, addr, subaddr, (void *)data, len);
        !           350: }
        !           351:
        !           352: int
        !           353: kiic_i2c_acquire_bus(void *cookie, int flags)
        !           354: {
        !           355:        struct kiic_bus *bus = cookie;
        !           356:
        !           357:        return (rw_enter(&bus->sc->sc_buslock, RW_WRITE));
        !           358: }
        !           359:
        !           360: void
        !           361: kiic_i2c_release_bus(void *cookie, int flags)
        !           362: {
        !           363:        struct kiic_bus *bus = cookie;
        !           364:
        !           365:        (void) rw_exit(&bus->sc->sc_buslock);
        !           366: }
        !           367:
        !           368: int
        !           369: kiic_i2c_exec(void *cookie, i2c_op_t op, i2c_addr_t addr,
        !           370:     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
        !           371: {
        !           372:        struct kiic_bus *bus = cookie;
        !           373:        u_int mode = I2C_STDSUBMODE;
        !           374:        u_int8_t cmd = 0;
        !           375:
        !           376:        if (!I2C_OP_STOP_P(op) || cmdlen > 1)
        !           377:                return (EINVAL);
        !           378:
        !           379:        if (cmdlen == 0)
        !           380:                mode = I2C_STDMODE;
        !           381:        else if (I2C_OP_READ_P(op))
        !           382:                mode = I2C_COMBMODE;
        !           383:
        !           384:        if (cmdlen > 0)
        !           385:                cmd = *(u_int8_t *)cmdbuf;
        !           386:
        !           387:        kiic_setmode(bus->sc, mode, bus->reg || addr & 0x80);
        !           388:        addr &= 0x7f;
        !           389:
        !           390:        if (I2C_OP_READ_P(op)) {
        !           391:                if (kiic_read(bus->sc, (addr << 1), cmd, buf, len) != 0)
        !           392:                        return (EIO);
        !           393:        } else {
        !           394:                if (kiic_write(bus->sc, (addr << 1), cmd, buf, len) != 0)
        !           395:                        return (EIO);
        !           396:        }
        !           397:        return (0);
        !           398: }

CVSweb