[BACK]Return to pcf8584.c CVS log [TXT][DIR] Up to [local] / sys / dev / ic

Annotation of sys/dev/ic/pcf8584.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pcf8584.c,v 1.8 2007/05/21 03:11:11 jsg Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2006 David Gwynne <dlg@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: #include <sys/param.h>
        !            20: #include <sys/systm.h>
        !            21: #include <sys/device.h>
        !            22: #include <sys/malloc.h>
        !            23: #include <sys/kernel.h>
        !            24: #include <sys/rwlock.h>
        !            25: #include <sys/proc.h>
        !            26:
        !            27: #include <machine/bus.h>
        !            28:
        !            29: #include <dev/i2c/i2cvar.h>
        !            30:
        !            31: #include <dev/ic/pcf8584var.h>
        !            32:
        !            33: #define PCF_S0                 0x00
        !            34: #define PCF_S1                 0x01
        !            35: #define PCF_S2                 0x02
        !            36: #define PCF_S3                 0x03
        !            37:
        !            38: #define PCF_CTRL_ACK           (1<<0)
        !            39: #define PCF_CTRL_STO           (1<<1)
        !            40: #define PCF_CTRL_STA           (1<<2)
        !            41: #define PCF_CTRL_ENI           (1<<3)
        !            42: #define PCF_CTRL_ES2           (1<<4)
        !            43: #define PCF_CTRL_ES1           (1<<5)
        !            44: #define PCF_CTRL_ESO           (1<<6)
        !            45: #define PCF_CTRL_PIN           (1<<7)
        !            46:
        !            47: #define PCF_CTRL_START         (PCF_CTRL_PIN | PCF_CTRL_ESO | \
        !            48:     PCF_CTRL_STA | PCF_CTRL_ACK)
        !            49: #define PCF_CTRL_STOP          (PCF_CTRL_PIN | PCF_CTRL_ESO | \
        !            50:     PCF_CTRL_STO | PCF_CTRL_ACK)
        !            51: #define PCF_CTRL_REPSTART      (PCF_CTRL_ESO | PCF_CTRL_STA | PCF_CTRL_ACK)
        !            52: #define PCF_CTRL_IDLE          (PCF_CTRL_PIN | PCF_CTRL_ESO | PCF_CTRL_ACK)
        !            53:
        !            54: #define PCF_STAT_nBB           (1<<0)
        !            55: #define PCF_STAT_LAB           (1<<1)
        !            56: #define PCF_STAT_AAS           (1<<2)
        !            57: #define PCF_STAT_AD0           (1<<3)
        !            58: #define PCF_STAT_LRB           (1<<3)
        !            59: #define PCF_STAT_BER           (1<<4)
        !            60: #define PCF_STAT_STS           (1<<5)
        !            61: #define PCF_STAT_PIN           (1<<7)
        !            62:
        !            63: #define PCF_FREQ_90            0x00 /* 90 kHz */
        !            64: #define PCF_FREQ_45            0x01 /* 45 kHz */
        !            65: #define PCF_FREQ_11            0x02 /* 11 kHz */
        !            66: #define PCF_FREQ_1_5           0x03 /* 1.5 kHz */
        !            67:
        !            68: struct cfdriver pcfiic_cd = {
        !            69:        NULL, "pcfiic", DV_DULL
        !            70: };
        !            71:
        !            72: void           pcfiic_init(struct pcfiic_softc *);
        !            73: int            pcfiic_i2c_acquire_bus(void *, int);
        !            74: void           pcfiic_i2c_release_bus(void *, int);
        !            75: int            pcfiic_i2c_exec(void *, i2c_op_t, i2c_addr_t, const void *,
        !            76:                    size_t, void *, size_t, int);
        !            77:
        !            78: int            pcfiic_xmit(struct pcfiic_softc *, u_int8_t, const u_int8_t *,
        !            79:                    size_t);
        !            80: int            pcfiic_recv(struct pcfiic_softc *, u_int8_t, u_int8_t *,
        !            81:                    size_t);
        !            82:
        !            83: volatile u_int8_t pcfiic_read(struct pcfiic_softc *, bus_size_t);
        !            84: volatile void  pcfiic_write(struct pcfiic_softc *, bus_size_t, u_int8_t);
        !            85: void           pcfiic_choose_bus(struct pcfiic_softc *, u_int8_t);
        !            86: int            pcfiic_wait_nBB(struct pcfiic_softc *);
        !            87: int            pcfiic_wait_pin(struct pcfiic_softc *, volatile u_int8_t *);
        !            88:
        !            89: void
        !            90: pcfiic_init(struct pcfiic_softc *sc)
        !            91: {
        !            92:        /* init S1 */
        !            93:        pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN);
        !            94:        /* own address */
        !            95:        pcfiic_write(sc, PCF_S0, sc->sc_addr);
        !            96:
        !            97:        /* select clock reg */
        !            98:        pcfiic_write(sc, PCF_S1, PCF_CTRL_PIN|PCF_CTRL_ES1);
        !            99:        pcfiic_write(sc, PCF_S0, sc->sc_clock);
        !           100:
        !           101:        pcfiic_write(sc, PCF_S1, PCF_CTRL_IDLE);
        !           102:
        !           103:        delay(200000);  /* Multi-Master mode, wait for longest i2c message */
        !           104: }
        !           105:
        !           106: void
        !           107: pcfiic_attach(struct pcfiic_softc *sc, i2c_addr_t addr, u_int8_t clock,
        !           108:     int swapregs,
        !           109:     void (*scan_func)(struct device *, struct i2cbus_attach_args *, void *),
        !           110:     void *scan_arg)
        !           111: {
        !           112:        struct i2cbus_attach_args               iba;
        !           113:
        !           114:        if (swapregs) {
        !           115:                sc->sc_regmap[PCF_S1] = PCF_S0;
        !           116:                sc->sc_regmap[PCF_S0] = PCF_S1;
        !           117:        } else {
        !           118:                sc->sc_regmap[PCF_S0] = PCF_S0;
        !           119:                sc->sc_regmap[PCF_S1] = PCF_S1;
        !           120:        }
        !           121:        sc->sc_clock = clock;
        !           122:        sc->sc_addr = addr;
        !           123:
        !           124:        pcfiic_init(sc);
        !           125:
        !           126:        printf("\n");
        !           127:
        !           128:        if (sc->sc_master)
        !           129:                pcfiic_choose_bus(sc, 0);
        !           130:
        !           131:        rw_init(&sc->sc_lock, "iiclk");
        !           132:        sc->sc_i2c.ic_cookie = sc;
        !           133:        sc->sc_i2c.ic_acquire_bus = pcfiic_i2c_acquire_bus;
        !           134:        sc->sc_i2c.ic_release_bus = pcfiic_i2c_release_bus;
        !           135:        sc->sc_i2c.ic_exec = pcfiic_i2c_exec;
        !           136:
        !           137:        bzero(&iba, sizeof(iba));
        !           138:        iba.iba_name = "iic";
        !           139:        iba.iba_tag = &sc->sc_i2c;
        !           140:        iba.iba_bus_scan = scan_func;
        !           141:        iba.iba_bus_scan_arg = scan_arg;
        !           142:        config_found(&sc->sc_dev, &iba, iicbus_print);
        !           143: }
        !           144:
        !           145: int
        !           146: pcfiic_intr(void *arg)
        !           147: {
        !           148:        return (0);
        !           149: }
        !           150:
        !           151: int
        !           152: pcfiic_i2c_acquire_bus(void *arg, int flags)
        !           153: {
        !           154:        struct pcfiic_softc     *sc = arg;
        !           155:
        !           156:        if (cold || sc->sc_poll || (flags & I2C_F_POLL))
        !           157:                return (0);
        !           158:
        !           159:        return (rw_enter(&sc->sc_lock, RW_WRITE | RW_INTR));
        !           160: }
        !           161:
        !           162: void
        !           163: pcfiic_i2c_release_bus(void *arg, int flags)
        !           164: {
        !           165:        struct pcfiic_softc     *sc = arg;
        !           166:
        !           167:        if (cold || sc->sc_poll || (flags & I2C_F_POLL))
        !           168:                return;
        !           169:
        !           170:        rw_exit(&sc->sc_lock);
        !           171: }
        !           172:
        !           173: int
        !           174: pcfiic_i2c_exec(void *arg, i2c_op_t op, i2c_addr_t addr,
        !           175:     const void *cmdbuf, size_t cmdlen, void *buf, size_t len, int flags)
        !           176: {
        !           177:        struct pcfiic_softc     *sc = arg;
        !           178:        int                     ret = 0;
        !           179:
        !           180: #if 0
        !           181:         printf("%s: exec op: %d addr: 0x%x cmdlen: %d len: %d flags 0x%x\n",
        !           182:             sc->sc_dev.dv_xname, op, addr, cmdlen, len, flags);
        !           183: #endif
        !           184:
        !           185:        if (cold || sc->sc_poll)
        !           186:                flags |= I2C_F_POLL;
        !           187:
        !           188:        if (sc->sc_master)
        !           189:                pcfiic_choose_bus(sc, addr >> 7);
        !           190:
        !           191:        if (cmdlen > 0)
        !           192:                if (pcfiic_xmit(sc, addr & 0x7f, cmdbuf, cmdlen) != 0)
        !           193:                        return (1);
        !           194:
        !           195:        if (len > 0) {
        !           196:                if (I2C_OP_WRITE_P(op))
        !           197:                        ret = pcfiic_xmit(sc, addr & 0x7f, buf, len);
        !           198:                else
        !           199:                        ret = pcfiic_recv(sc, addr & 0x7f, buf, len);
        !           200:        }
        !           201:        return (ret);
        !           202: }
        !           203:
        !           204: int
        !           205: pcfiic_xmit(struct pcfiic_softc *sc, u_int8_t addr, const u_int8_t *buf,
        !           206:     size_t len)
        !           207: {
        !           208:        int                     i, err = 0;
        !           209:        volatile u_int8_t       r;
        !           210:
        !           211:        if (pcfiic_wait_nBB(sc) != 0)
        !           212:                return (1);
        !           213:
        !           214:        pcfiic_write(sc, PCF_S0, addr << 1);
        !           215:        pcfiic_write(sc, PCF_S1, PCF_CTRL_START);
        !           216:
        !           217:        for (i = 0; i <= len; i++) {
        !           218:                if (pcfiic_wait_pin(sc, &r) != 0) {
        !           219:                        pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
        !           220:                        return (1);
        !           221:                }
        !           222:
        !           223:                if (r & PCF_STAT_LRB) {
        !           224:                        err = 1;
        !           225:                        break;
        !           226:                }
        !           227:
        !           228:                if (i < len)
        !           229:                        pcfiic_write(sc, PCF_S0, buf[i]);
        !           230:        }
        !           231:        pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
        !           232:        return (err);
        !           233: }
        !           234:
        !           235: int
        !           236: pcfiic_recv(struct pcfiic_softc *sc, u_int8_t addr, u_int8_t *buf, size_t len)
        !           237: {
        !           238:        int                     i = 0, err = 0;
        !           239:        volatile u_int8_t       r;
        !           240:
        !           241:        if (pcfiic_wait_nBB(sc) != 0)
        !           242:                return (1);
        !           243:
        !           244:        pcfiic_write(sc, PCF_S0, (addr << 1) | 0x01);
        !           245:        pcfiic_write(sc, PCF_S1, PCF_CTRL_START);
        !           246:
        !           247:        for (i = 0; i <= len; i++) {
        !           248:                if (pcfiic_wait_pin(sc, &r) != 0) {
        !           249:                        pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
        !           250:                        return (1);
        !           251:                }
        !           252:
        !           253:                if ((i != len) && (r & PCF_STAT_LRB)) {
        !           254:                        pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
        !           255:                        return (1);
        !           256:                }
        !           257:
        !           258:                if (i == len - 1) {
        !           259:                        pcfiic_write(sc, PCF_S1, PCF_CTRL_ESO);
        !           260:                } else if (i == len) {
        !           261:                        pcfiic_write(sc, PCF_S1, PCF_CTRL_STOP);
        !           262:                }
        !           263:
        !           264:                r = pcfiic_read(sc, PCF_S0);
        !           265:                if (i > 0)
        !           266:                        buf[i - 1] = r;
        !           267:        }
        !           268:        return (err);
        !           269: }
        !           270:
        !           271: volatile u_int8_t
        !           272: pcfiic_read(struct pcfiic_softc *sc, bus_size_t r)
        !           273: {
        !           274:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], 1,
        !           275:            BUS_SPACE_BARRIER_READ);
        !           276:        return (bus_space_read_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r]));
        !           277: }
        !           278:
        !           279: volatile void
        !           280: pcfiic_write(struct pcfiic_softc *sc, bus_size_t r, u_int8_t v)
        !           281: {
        !           282:        bus_space_write_1(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], v);
        !           283:        bus_space_barrier(sc->sc_iot, sc->sc_ioh, sc->sc_regmap[r], 1,
        !           284:            BUS_SPACE_BARRIER_WRITE);
        !           285: }
        !           286:
        !           287: void
        !           288: pcfiic_choose_bus(struct pcfiic_softc *sc, u_int8_t bus)
        !           289: {
        !           290:        bus_space_write_1(sc->sc_iot, sc->sc_ioh2, 0, bus);
        !           291:        bus_space_barrier(sc->sc_iot, sc->sc_ioh2, 0, 1,
        !           292:            BUS_SPACE_BARRIER_WRITE);
        !           293: }
        !           294:
        !           295: int
        !           296: pcfiic_wait_nBB(struct pcfiic_softc *sc)
        !           297: {
        !           298:        int             i;
        !           299:
        !           300:        for (i = 0; i < 1000; i++) {
        !           301:                if (pcfiic_read(sc, PCF_S1) & PCF_STAT_nBB)
        !           302:                        return (0);
        !           303:                delay(1000);
        !           304:        }
        !           305:        return (1);
        !           306: }
        !           307:
        !           308: int
        !           309: pcfiic_wait_pin(struct pcfiic_softc *sc, volatile u_int8_t *r)
        !           310: {
        !           311:        int             i;
        !           312:
        !           313:        for (i = 0; i < 1000; i++) {
        !           314:                *r = pcfiic_read(sc, PCF_S1);
        !           315:                if ((*r & PCF_STAT_PIN) == 0)
        !           316:                        return (0);
        !           317:                delay(1000);
        !           318:        }
        !           319:        return (1);
        !           320: }

CVSweb