[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

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