1 /* $OpenBSD: pca9532.c,v 1.4 2022/04/06 18:59:28 naddy Exp $ */ 2 /* 3 * Copyright (c) 2006 Dale Rahn <drahn@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/param.h> 19 #include <sys/systm.h> 20 #include <sys/device.h> 21 #include <sys/kernel.h> 22 #include <sys/fcntl.h> 23 #include <sys/uio.h> 24 #include <sys/conf.h> 25 #include <sys/gpio.h> 26 27 28 #include <dev/i2c/i2cvar.h> 29 #include <dev/gpio/gpiovar.h> 30 31 #include "gpio.h" 32 33 /* driver for PCA 9532 */ 34 35 #define PCALED_ADDR 0x60 36 37 #define PCALED_GPIO_NPINS 16 38 39 struct pcaled_softc { 40 struct device sc_dev; 41 i2c_tag_t sc_tag; 42 int sc_addr; 43 struct gpio_chipset_tag sc_gpio_gc; 44 struct gpio_pin sc_gpio_pin[PCALED_GPIO_NPINS]; 45 46 }; 47 48 int pcaled_match(struct device *, void *, void *); 49 void pcaled_attach(struct device *, struct device *, void *); 50 int pcaled_gpio_pin_read(void *arg, int pin); 51 void pcaled_gpio_pin_write (void *arg, int pin, int value); 52 void pcaled_gpio_pin_ctl (void *arg, int pin, int flags); 53 54 const struct cfattach pcaled_ca = { 55 sizeof(struct pcaled_softc), pcaled_match, pcaled_attach 56 }; 57 58 struct cfdriver pcaled_cd = { 59 NULL, "pcaled", DV_DULL 60 }; 61 62 int 63 pcaled_match(struct device *parent, void *v, void *arg) 64 { 65 struct i2c_attach_args *ia = arg; 66 int ok = 0; 67 uint8_t cmd, data; 68 69 if (ia->ia_addr != PCALED_ADDR) 70 return (0); 71 /* attempt to read input register 0 */ 72 iic_acquire_bus(ia->ia_tag, I2C_F_POLL); 73 cmd = 0; 74 if (iic_exec(ia->ia_tag, I2C_OP_READ_WITH_STOP, ia->ia_addr, 75 &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) 76 goto fail; 77 cmd = 9; 78 if (iic_exec(ia->ia_tag, I2C_OP_READ_WITH_STOP, ia->ia_addr, 79 &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) 80 goto fail; 81 ok = 1; 82 fail: 83 iic_release_bus(ia->ia_tag, I2C_F_POLL); 84 return (ok); 85 } 86 87 void 88 pcaled_attach(struct device *parent, struct device *self, void *arg) 89 { 90 struct pcaled_softc *sc = (void *)self; 91 struct i2c_attach_args *ia = arg; 92 struct gpiobus_attach_args gba; 93 int i; 94 uint8_t cmd, data; 95 96 sc->sc_tag = ia->ia_tag; 97 sc->sc_addr = ia->ia_addr; 98 99 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 100 101 for (i = 0; i < PCALED_GPIO_NPINS; i++) { 102 sc->sc_gpio_pin[i].pin_num = i; 103 sc->sc_gpio_pin[i].pin_caps = GPIO_PIN_INOUT; 104 if (i < 8) 105 cmd = 0; 106 else 107 cmd = 1; 108 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 109 &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) 110 goto fail; /* XXX */ 111 sc->sc_gpio_pin[i].pin_state = (data >> (i & 3)) & 1; 112 } 113 sc->sc_gpio_gc.gp_cookie = sc; 114 sc->sc_gpio_gc.gp_pin_read = pcaled_gpio_pin_read; 115 sc->sc_gpio_gc.gp_pin_write = pcaled_gpio_pin_write; 116 sc->sc_gpio_gc.gp_pin_ctl = pcaled_gpio_pin_ctl; 117 118 printf(": PCA9532 LED controller\n"); 119 120 gba.gba_name = "gpio"; 121 gba.gba_gc = &sc->sc_gpio_gc; 122 gba.gba_pins = sc->sc_gpio_pin; 123 gba.gba_npins = PCALED_GPIO_NPINS; 124 #if NGPIO > 0 125 config_found(&sc->sc_dev, &gba, gpiobus_print); 126 #endif 127 128 fail: 129 iic_release_bus(sc->sc_tag, I2C_F_POLL); 130 } 131 132 int 133 pcaled_gpio_pin_read(void *arg, int pin) 134 { 135 struct pcaled_softc *sc = arg; 136 iic_acquire_bus(sc->sc_tag, I2C_F_POLL); 137 uint8_t cmd, data; 138 139 if (pin < 8) 140 cmd = 0; 141 else 142 cmd = 1; 143 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 144 &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) 145 goto fail; /* XXX */ 146 147 fail: 148 iic_release_bus(sc->sc_tag, I2C_F_POLL); 149 return (data >> (pin & 3)) & 1; 150 } 151 152 void 153 pcaled_gpio_pin_write (void *arg, int pin, int value) 154 { 155 struct pcaled_softc *sc = arg; 156 uint8_t cmd, data; 157 if (pin < 4) 158 cmd = 6; 159 else if (pin < 8) 160 cmd = 7; 161 else if (pin < 12) 162 cmd = 8; 163 else 164 cmd = 9; 165 if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP, sc->sc_addr, 166 &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) 167 goto fail; /* XXX */ 168 data &= ~(0x3 << (2*(pin & 3))); 169 data |= (value << (2*(pin & 3))); 170 171 if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_addr, 172 &cmd, sizeof cmd, &data, sizeof data, I2C_F_POLL)) 173 goto fail; /* XXX */ 174 175 fail: 176 iic_release_bus(sc->sc_tag, I2C_F_POLL); 177 } 178 179 void 180 pcaled_gpio_pin_ctl (void *arg, int pin, int flags) 181 { 182 /* XXX all pins are inout */ 183 } 184 185