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

Annotation of sys/dev/i2c/pca9554.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pca9554.c,v 1.14 2007/07/31 21:34:39 cnst Exp $       */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2005 Theo de Raadt
        !             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/gpio.h>
        !            23: #include <sys/sensors.h>
        !            24:
        !            25: #include <dev/i2c/i2cvar.h>
        !            26:
        !            27: #include <dev/gpio/gpiovar.h>
        !            28:
        !            29: /* Phillips 9554 registers */
        !            30: #define PCA9554_IN             0x00
        !            31: #define PCA9554_OUT            0x01
        !            32: #define PCA9554_POLARITY       0x02
        !            33: #define PCA9554_CONFIG         0x03
        !            34:
        !            35: /* Sensors */
        !            36: #define PCAGPIO_NPINS  8
        !            37:
        !            38: struct pcagpio_softc {
        !            39:        struct device   sc_dev;
        !            40:        i2c_tag_t       sc_tag;
        !            41:        i2c_addr_t      sc_addr;
        !            42:        u_int8_t        sc_control;
        !            43:        u_int8_t        sc_polarity;
        !            44:
        !            45:        struct gpio_chipset_tag sc_gpio_gc;
        !            46:         gpio_pin_t sc_gpio_pins[PCAGPIO_NPINS];
        !            47:
        !            48:        struct ksensor sc_sensor[PCAGPIO_NPINS];
        !            49:        struct ksensordev sc_sensordev;
        !            50: };
        !            51:
        !            52: int    pcagpio_match(struct device *, void *, void *);
        !            53: void   pcagpio_attach(struct device *, struct device *, void *);
        !            54: int    pcagpio_check(struct i2c_attach_args *, u_int8_t *, u_int8_t *);
        !            55: void   pcagpio_refresh(void *);
        !            56:
        !            57: int     pcagpio_gpio_pin_read(void *, int);
        !            58: void    pcagpio_gpio_pin_write(void *, int, int);
        !            59: void    pcagpio_gpio_pin_ctl(void *, int, int);
        !            60:
        !            61: struct cfattach pcagpio_ca = {
        !            62:        sizeof(struct pcagpio_softc), pcagpio_match, pcagpio_attach
        !            63: };
        !            64:
        !            65: struct cfdriver pcagpio_cd = {
        !            66:        NULL, "pcagpio", DV_DULL
        !            67: };
        !            68:
        !            69: int
        !            70: pcagpio_match(struct device *parent, void *match, void *aux)
        !            71: {
        !            72:        struct i2c_attach_args *ia = aux;
        !            73:
        !            74:        if (strcmp(ia->ia_name, "PCA9554") == 0 ||
        !            75:            strcmp(ia->ia_name, "PCA9554M") == 0 ||
        !            76:            strcmp(ia->ia_name, "pca9555") == 0 ||
        !            77:            strcmp(ia->ia_name, "pca9556") == 0 ||
        !            78:            strcmp(ia->ia_name, "pca9557") == 0)
        !            79:                return (1);
        !            80:        return (0);
        !            81: }
        !            82:
        !            83: void
        !            84: pcagpio_attach(struct device *parent, struct device *self, void *aux)
        !            85: {
        !            86:        struct pcagpio_softc *sc = (struct pcagpio_softc *)self;
        !            87:        struct i2c_attach_args *ia = aux;
        !            88:        struct gpiobus_attach_args gba;
        !            89:        u_int8_t cmd, data;
        !            90:        int outputs = 0, i;
        !            91:
        !            92:        sc->sc_tag = ia->ia_tag;
        !            93:        sc->sc_addr = ia->ia_addr;
        !            94:
        !            95:        cmd = PCA9554_CONFIG;
        !            96:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
        !            97:            sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
        !            98:                printf(": failed to initialize\n");
        !            99:                return;
        !           100:        }
        !           101:        sc->sc_control = data;
        !           102:        cmd = PCA9554_POLARITY;
        !           103:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
        !           104:            sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
        !           105:                printf(": failed to initialize\n");
        !           106:                return;
        !           107:        }
        !           108:        sc->sc_polarity = data;
        !           109:        cmd = PCA9554_OUT;
        !           110:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
        !           111:            sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) {
        !           112:                printf(": failed to initialize\n");
        !           113:                return;
        !           114:        }
        !           115:
        !           116:        /* Initialize sensor data. */
        !           117:        strlcpy(sc->sc_sensordev.xname, sc->sc_dev.dv_xname,
        !           118:            sizeof(sc->sc_sensordev.xname));
        !           119:
        !           120:        for (i = 0; i < PCAGPIO_NPINS; i++) {
        !           121:                sc->sc_sensor[i].type = SENSOR_INDICATOR;
        !           122:                if ((sc->sc_control & (1 << i)) == 0) {
        !           123:                        strlcpy(sc->sc_sensor[i].desc, "out",
        !           124:                            sizeof(sc->sc_sensor[i].desc));
        !           125:                        outputs++;
        !           126:                } else
        !           127:                        strlcpy(sc->sc_sensor[i].desc, "in",
        !           128:                            sizeof(sc->sc_sensor[i].desc));
        !           129:
        !           130:        }
        !           131:
        !           132:        if (sensor_task_register(sc, pcagpio_refresh, 5) == NULL) {
        !           133:                printf(", unable to register update task\n");
        !           134:                return;
        !           135:        }
        !           136:
        !           137: #if 0
        !           138:        for (i = 0; i < PCAGPIO_NPINS; i++)
        !           139:                sensor_attach(&sc->sc_sensordev, &sc->sc_sensor[i]);
        !           140:        sensordev_install(&sc->sc_sensordev);
        !           141: #endif
        !           142:
        !           143:        printf(":");
        !           144:        if (PCAGPIO_NPINS - outputs)
        !           145:                printf(" %d inputs", PCAGPIO_NPINS - outputs);
        !           146:        if (outputs)
        !           147:                printf(" %d outputs", outputs);
        !           148:        printf("\n");
        !           149:
        !           150:        for (i = 0; i < PCAGPIO_NPINS; i++) {
        !           151:                sc->sc_gpio_pins[i].pin_num = i;
        !           152:                sc->sc_gpio_pins[i].pin_caps = GPIO_PIN_INPUT | GPIO_PIN_OUTPUT;
        !           153:
        !           154:                if ((sc->sc_control & (1 << i)) == 0) {
        !           155:                        sc->sc_gpio_pins[i].pin_flags = GPIO_PIN_OUTPUT;
        !           156:                        sc->sc_gpio_pins[i].pin_state =
        !           157:                            data & (1 << i) ? GPIO_PIN_HIGH : GPIO_PIN_LOW;
        !           158:                }
        !           159:        }
        !           160:
        !           161:        /* Create controller tag */
        !           162:        sc->sc_gpio_gc.gp_cookie = sc;
        !           163:        sc->sc_gpio_gc.gp_pin_read = pcagpio_gpio_pin_read;
        !           164:        sc->sc_gpio_gc.gp_pin_write = pcagpio_gpio_pin_write;
        !           165:        sc->sc_gpio_gc.gp_pin_ctl = pcagpio_gpio_pin_ctl;
        !           166:
        !           167:        gba.gba_name = "gpio";
        !           168:        gba.gba_gc = &sc->sc_gpio_gc;
        !           169:        gba.gba_pins = sc->sc_gpio_pins;
        !           170:        gba.gba_npins = PCAGPIO_NPINS;
        !           171:
        !           172:        config_found(&sc->sc_dev, &gba, gpiobus_print);
        !           173:
        !           174: }
        !           175:
        !           176: void
        !           177: pcagpio_refresh(void *arg)
        !           178: {
        !           179:        struct pcagpio_softc *sc = arg;
        !           180:        u_int8_t cmd, in, out, bit;
        !           181:        int i;
        !           182:
        !           183:        iic_acquire_bus(sc->sc_tag, 0);
        !           184:
        !           185:        cmd = PCA9554_IN;
        !           186:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
        !           187:            sc->sc_addr, &cmd, sizeof cmd, &in, sizeof in, 0))
        !           188:                goto invalid;
        !           189:
        !           190:        cmd = PCA9554_OUT;
        !           191:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
        !           192:            sc->sc_addr, &cmd, sizeof cmd, &out, sizeof out, 0))
        !           193:                goto invalid;
        !           194:
        !           195:        for (i = 0; i < PCAGPIO_NPINS; i++) {
        !           196:                bit = 1 << i;
        !           197:                if ((sc->sc_control & bit))
        !           198:                        sc->sc_sensor[i].value = (in & bit) ? 1 : 0;
        !           199:                else
        !           200:                        sc->sc_sensor[i].value = (out & bit) ? 1 : 0;
        !           201:        }
        !           202:
        !           203: invalid:
        !           204:        iic_release_bus(sc->sc_tag, 0);
        !           205: }
        !           206:
        !           207:
        !           208: int
        !           209: pcagpio_gpio_pin_read(void *arg, int pin)
        !           210: {
        !           211:        struct pcagpio_softc *sc = arg;
        !           212:        u_int8_t cmd, in;
        !           213:
        !           214:        cmd = PCA9554_IN;
        !           215:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
        !           216:            sc->sc_addr, &cmd, sizeof cmd, &in, sizeof in, 0))
        !           217:                return 0;
        !           218:        return ((in ^ sc->sc_polarity) & (1 << pin)) ? 1 : 0;
        !           219: }
        !           220:
        !           221: void
        !           222: pcagpio_gpio_pin_write(void *arg, int pin, int value)
        !           223: {
        !           224:        struct pcagpio_softc *sc = arg;
        !           225:        u_int8_t cmd, out, mask;
        !           226:
        !           227:        mask = 0xff ^ (1 << pin);
        !           228:        cmd = PCA9554_OUT;
        !           229:        if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
        !           230:            sc->sc_addr, &cmd, sizeof cmd, &out, sizeof out, 0))
        !           231:                return;
        !           232:        out = (out & mask) | (value << pin);
        !           233:
        !           234:        cmd = PCA9554_OUT;
        !           235:        if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
        !           236:            sc->sc_addr, &cmd, sizeof cmd, &out, sizeof out, 0))
        !           237:                return;
        !           238: }
        !           239:
        !           240: void
        !           241: pcagpio_gpio_pin_ctl(void *arg, int pin, int flags)
        !           242: {
        !           243: #if 0
        !           244:        struct pcagpio_softc *sc = arg;
        !           245:        u_int32_t conf;
        !           246:
        !           247:        pcagpio_gpio_pin_select(sc, pin);
        !           248:        conf = bus_space_read_4(sc->sc_gpio_iot, sc->sc_gpio_ioh,
        !           249:            GSCGPIO_CONF);
        !           250:
        !           251:        conf &= ~(GSCGPIO_CONF_OUTPUTEN | GSCGPIO_CONF_PUSHPULL |
        !           252:            GSCGPIO_CONF_PULLUP);
        !           253:        if ((flags & GPIO_PIN_TRISTATE) == 0)
        !           254:                conf |= GSCGPIO_CONF_OUTPUTEN;
        !           255:        if (flags & GPIO_PIN_PUSHPULL)
        !           256:                conf |= GSCGPIO_CONF_PUSHPULL;
        !           257:        if (flags & GPIO_PIN_PULLUP)
        !           258:                conf |= GSCGPIO_CONF_PULLUP;
        !           259:        bus_space_write_4(sc->sc_gpio_iot, sc->sc_gpio_ioh,
        !           260:            GSCGPIO_CONF, conf);
        !           261: #endif
        !           262: }

CVSweb