1 /* $OpenBSD: pca9554.c,v 1.18 2018/07/09 18:48:52 patrick 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 23 #include <dev/i2c/i2cvar.h> 24 25 #include <dev/ofw/openfirm.h> 26 #include <dev/ofw/ofw_gpio.h> 27 28 /* Philips 9554/6/7 registers */ 29 #define PCA9554_IN 0x00 30 #define PCA9554_OUT 0x01 31 #define PCA9554_POLARITY 0x02 32 #define PCA9554_CONFIG 0x03 33 34 /* Philips 9555 registers */ 35 #define PCA9555_IN0 0x00 36 #define PCA9555_IN1 0x01 37 #define PCA9555_OUT0 0x02 38 #define PCA9555_OUT1 0x03 39 #define PCA9555_POLARITY0 0x04 40 #define PCA9555_POLARITY1 0x05 41 #define PCA9555_CONFIG0 0x06 42 #define PCA9555_CONFIG1 0x07 43 44 /* Sensors */ 45 #define PCAGPIO_NPINS 16 46 47 #define PCAGPIO_NPORTS 2 48 #define PCAGPIO_PORT(_pin) ((_pin) > 7 ? 1 : 0) 49 #define PCAGPIO_BIT(_pin) (1 << ((_pin) % 8)) 50 51 /* Register mapping index */ 52 enum pcigpio_cmd { 53 PCAGPIO_IN = 0, 54 PCAGPIO_OUT, 55 PCAGPIO_POLARITY, 56 PCAGPIO_CONFIG, 57 PCAGPIO_MAX 58 }; 59 60 struct pcagpio_softc { 61 struct device sc_dev; 62 i2c_tag_t sc_tag; 63 i2c_addr_t sc_addr; 64 int sc_node; 65 66 u_int8_t sc_npins; 67 u_int8_t sc_regs[PCAGPIO_NPORTS][PCAGPIO_MAX]; 68 69 struct gpio_controller sc_gc; 70 }; 71 72 int pcagpio_match(struct device *, void *, void *); 73 void pcagpio_attach(struct device *, struct device *, void *); 74 int pcagpio_init(struct pcagpio_softc *, int); 75 76 void pcagpio_config_pin(void *, uint32_t *, int); 77 int pcagpio_get_pin(void *, uint32_t *); 78 void pcagpio_set_pin(void *, uint32_t *, int); 79 80 struct cfattach pcagpio_ca = { 81 sizeof(struct pcagpio_softc), pcagpio_match, pcagpio_attach 82 }; 83 84 struct cfdriver pcagpio_cd = { 85 NULL, "pcagpio", DV_DULL 86 }; 87 88 int 89 pcagpio_match(struct device *parent, void *match, void *aux) 90 { 91 struct i2c_attach_args *ia = aux; 92 93 if (strcmp(ia->ia_name, "nxp,pca9554") == 0 || 94 strcmp(ia->ia_name, "nxp,pca9555") == 0 || 95 strcmp(ia->ia_name, "nxp,pca9557") == 0) 96 return (1); 97 return (0); 98 } 99 100 void 101 pcagpio_attach(struct device *parent, struct device *self, void *aux) 102 { 103 struct pcagpio_softc *sc = (struct pcagpio_softc *)self; 104 struct i2c_attach_args *ia = aux; 105 106 sc->sc_tag = ia->ia_tag; 107 sc->sc_addr = ia->ia_addr; 108 sc->sc_node = *(int *)ia->ia_cookie; 109 110 if (strcmp(ia->ia_name, "nxp,pca9555") == 0) { 111 /* The pca9555 has two 8 bit ports */ 112 sc->sc_regs[0][PCAGPIO_IN] = PCA9555_IN0; 113 sc->sc_regs[0][PCAGPIO_OUT] = PCA9555_OUT0; 114 sc->sc_regs[0][PCAGPIO_POLARITY] = PCA9555_POLARITY0; 115 sc->sc_regs[0][PCAGPIO_CONFIG] = PCA9555_CONFIG0; 116 sc->sc_regs[1][PCAGPIO_IN] = PCA9555_IN1; 117 sc->sc_regs[1][PCAGPIO_OUT] = PCA9555_OUT1; 118 sc->sc_regs[1][PCAGPIO_POLARITY] = PCA9555_POLARITY1; 119 sc->sc_regs[1][PCAGPIO_CONFIG] = PCA9555_CONFIG1; 120 sc->sc_npins = 16; 121 } else { 122 /* All other supported devices have one 8 bit port */ 123 sc->sc_regs[0][PCAGPIO_IN] = PCA9554_IN; 124 sc->sc_regs[0][PCAGPIO_OUT] = PCA9554_OUT; 125 sc->sc_regs[0][PCAGPIO_POLARITY] = PCA9554_POLARITY; 126 sc->sc_regs[0][PCAGPIO_CONFIG] = PCA9554_CONFIG; 127 sc->sc_npins = 8; 128 } 129 if (pcagpio_init(sc, 0) != 0) 130 return; 131 if (sc->sc_npins > 8 && pcagpio_init(sc, 1) != 0) 132 return; 133 134 printf("\n"); 135 136 /* Create controller tag */ 137 sc->sc_gc.gc_node = sc->sc_node; 138 sc->sc_gc.gc_cookie = sc; 139 sc->sc_gc.gc_config_pin = pcagpio_config_pin; 140 sc->sc_gc.gc_get_pin = pcagpio_get_pin; 141 sc->sc_gc.gc_set_pin = pcagpio_set_pin; 142 gpio_controller_register(&sc->sc_gc); 143 } 144 145 int 146 pcagpio_init(struct pcagpio_softc *sc, int port) 147 { 148 u_int8_t cmd, data; 149 150 /* Don't invert input. */ 151 data = 0; 152 cmd = sc->sc_regs[port][PCAGPIO_POLARITY]; 153 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 154 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) { 155 printf(": failed to initialize\n"); 156 return (-1); 157 } 158 159 return (0); 160 } 161 162 void 163 pcagpio_config_pin(void *arg, uint32_t *cells, int config) 164 { 165 struct pcagpio_softc *sc = arg; 166 uint32_t pin = cells[0]; 167 u_int8_t cmd, data; 168 int port, bit; 169 170 if (pin >= 16) 171 return; 172 173 port = PCAGPIO_PORT(pin); 174 bit = PCAGPIO_BIT(pin); 175 176 cmd = sc->sc_regs[port][PCAGPIO_CONFIG]; 177 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 178 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) 179 return; 180 181 if (config & GPIO_CONFIG_OUTPUT) 182 data &= ~bit; 183 else 184 data |= bit; 185 186 cmd = sc->sc_regs[port][PCAGPIO_CONFIG]; 187 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 188 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) 189 return; 190 } 191 192 int 193 pcagpio_get_pin(void *arg, uint32_t *cells) 194 { 195 struct pcagpio_softc *sc = arg; 196 uint32_t pin = cells[0]; 197 uint32_t flags = cells[1]; 198 u_int8_t cmd, data; 199 int port, bit, value; 200 201 if (pin >= 16) 202 return 0; 203 204 port = PCAGPIO_PORT(pin); 205 bit = PCAGPIO_BIT(pin); 206 207 cmd = sc->sc_regs[port][PCAGPIO_IN]; 208 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 209 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) 210 return 0; 211 212 value = !!(data & bit); 213 if (flags & GPIO_ACTIVE_LOW) 214 value = !value; 215 216 return value; 217 } 218 219 void 220 pcagpio_set_pin(void *arg, uint32_t *cells, int value) 221 { 222 struct pcagpio_softc *sc = arg; 223 uint32_t pin = cells[0]; 224 uint32_t flags = cells[1]; 225 u_int8_t cmd, data; 226 int port, bit; 227 228 if (pin >= 16) 229 return; 230 231 port = PCAGPIO_PORT(pin); 232 bit = PCAGPIO_BIT(pin); 233 234 cmd = sc->sc_regs[port][PCAGPIO_OUT]; 235 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, 236 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) 237 return; 238 239 if (flags & GPIO_ACTIVE_LOW) 240 value = !value; 241 242 data &= ~bit; 243 if (value) 244 data |= bit; 245 246 cmd = sc->sc_regs[port][PCAGPIO_OUT]; 247 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, 248 sc->sc_addr, &cmd, sizeof cmd, &data, sizeof data, 0)) 249 return; 250 } 251