[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

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