root/dev/i2c/pca9554.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pcagpio_match
  2. pcagpio_attach
  3. pcagpio_refresh
  4. pcagpio_gpio_pin_read
  5. pcagpio_gpio_pin_write
  6. pcagpio_gpio_pin_ctl

    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 }

/* [<][>][^][v][top][bottom][index][help] */