1 1.20 thorpej /* $NetBSD: viapcib.c,v 1.20 2025/09/15 13:23:01 thorpej Exp $ */ 2 1.1 jmcneill /* $FreeBSD: src/sys/pci/viapm.c,v 1.10 2005/05/29 04:42:29 nyan Exp $ */ 3 1.1 jmcneill 4 1.1 jmcneill /*- 5 1.1 jmcneill * Copyright (c) 2005, 2006 Jared D. McNeill <jmcneill (at) invisible.ca> 6 1.1 jmcneill * All rights reserved. 7 1.1 jmcneill * 8 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 9 1.1 jmcneill * modification, are permitted provided that the following conditions 10 1.1 jmcneill * are met: 11 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 12 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 13 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 14 1.1 jmcneill * notice, this list of conditions, and the following disclaimer in the 15 1.1 jmcneill * documentation and/or other materials provided with the distribution. 16 1.1 jmcneill * 3. The name of the author may not be used to endorse or promote products 17 1.1 jmcneill * derived from this software without specific prior written permission. 18 1.1 jmcneill * 19 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 20 1.1 jmcneill * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 1.1 jmcneill * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 22 1.1 jmcneill * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 23 1.1 jmcneill * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 24 1.1 jmcneill * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 1.1 jmcneill * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 1.1 jmcneill * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 27 1.1 jmcneill * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 1.1 jmcneill * SUCH DAMAGE. 30 1.1 jmcneill */ 31 1.1 jmcneill /*- 32 1.1 jmcneill * Copyright (c) 2001 Alcove - Nicolas Souchu 33 1.1 jmcneill * All rights reserved. 34 1.1 jmcneill * 35 1.1 jmcneill * Redistribution and use in source and binary forms, with or without 36 1.1 jmcneill * modification, are permitted provided that the following conditions 37 1.1 jmcneill * are met: 38 1.1 jmcneill * 1. Redistributions of source code must retain the above copyright 39 1.1 jmcneill * notice, this list of conditions and the following disclaimer. 40 1.1 jmcneill * 2. Redistributions in binary form must reproduce the above copyright 41 1.1 jmcneill * notice, this list of conditions and the following disclaimer in the 42 1.1 jmcneill * documentation and/or other materials provided with the distribution. 43 1.1 jmcneill * 44 1.1 jmcneill * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 45 1.1 jmcneill * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 46 1.1 jmcneill * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 47 1.1 jmcneill * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 48 1.1 jmcneill * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 49 1.1 jmcneill * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 50 1.1 jmcneill * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 51 1.1 jmcneill * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 52 1.1 jmcneill * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 53 1.1 jmcneill * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 54 1.1 jmcneill * SUCH DAMAGE. 55 1.1 jmcneill */ 56 1.1 jmcneill 57 1.1 jmcneill #include <sys/cdefs.h> 58 1.20 thorpej __KERNEL_RCSID(0, "$NetBSD: viapcib.c,v 1.20 2025/09/15 13:23:01 thorpej Exp $"); 59 1.1 jmcneill 60 1.1 jmcneill #include <sys/types.h> 61 1.1 jmcneill #include <sys/param.h> 62 1.1 jmcneill #include <sys/systm.h> 63 1.1 jmcneill #include <sys/device.h> 64 1.13 rmind #include <sys/mutex.h> 65 1.7 ad #include <sys/bus.h> 66 1.1 jmcneill 67 1.1 jmcneill #include <dev/pci/pcireg.h> 68 1.1 jmcneill #include <dev/pci/pcivar.h> 69 1.1 jmcneill #include <dev/pci/pcidevs.h> 70 1.1 jmcneill 71 1.1 jmcneill #include <dev/i2c/i2cvar.h> 72 1.1 jmcneill 73 1.1 jmcneill #include <i386/pci/viapcibreg.h> 74 1.11 martin #include <x86/pci/pcibvar.h> 75 1.1 jmcneill 76 1.1 jmcneill /*#define VIAPCIB_DEBUG*/ 77 1.1 jmcneill 78 1.1 jmcneill #ifdef VIAPCIB_DEBUG 79 1.1 jmcneill #define DPRINTF(x) printf x 80 1.1 jmcneill #else 81 1.1 jmcneill #define DPRINTF(x) 82 1.1 jmcneill #endif 83 1.1 jmcneill 84 1.1 jmcneill struct viapcib_softc { 85 1.11 martin /* we call pcibattach(), which assumes softc starts like this: */ 86 1.11 martin struct pcib_softc sc_pcib; 87 1.11 martin 88 1.1 jmcneill bus_space_tag_t sc_iot; 89 1.1 jmcneill bus_space_handle_t sc_ioh; 90 1.1 jmcneill struct i2c_controller sc_i2c; 91 1.1 jmcneill 92 1.1 jmcneill int sc_revision; 93 1.1 jmcneill }; 94 1.1 jmcneill 95 1.10 xtraeme static int viapcib_match(device_t, cfdata_t, void *); 96 1.10 xtraeme static void viapcib_attach(device_t, device_t, void *); 97 1.1 jmcneill 98 1.1 jmcneill static int viapcib_clear(struct viapcib_softc *); 99 1.1 jmcneill static int viapcib_busy(struct viapcib_softc *); 100 1.1 jmcneill 101 1.1 jmcneill #define viapcib_smbus_read(sc, o) \ 102 1.1 jmcneill bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (o)) 103 1.1 jmcneill #define viapcib_smbus_write(sc, o, v) \ 104 1.1 jmcneill bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (o), (v)) 105 1.1 jmcneill 106 1.1 jmcneill #define VIAPCIB_SMBUS_TIMEOUT 10000 107 1.1 jmcneill 108 1.1 jmcneill static int viapcib_exec(void *, i2c_op_t, i2c_addr_t, const void *, 109 1.1 jmcneill size_t, void *, size_t, int); 110 1.1 jmcneill 111 1.1 jmcneill /* SMBus operations */ 112 1.1 jmcneill static int viapcib_smbus_quick_write(void *, i2c_addr_t); 113 1.1 jmcneill static int viapcib_smbus_quick_read(void *, i2c_addr_t); 114 1.1 jmcneill static int viapcib_smbus_send_byte(void *, i2c_addr_t, uint8_t); 115 1.1 jmcneill static int viapcib_smbus_receive_byte(void *, i2c_addr_t, 116 1.1 jmcneill uint8_t *); 117 1.1 jmcneill static int viapcib_smbus_read_byte(void *, i2c_addr_t, uint8_t, 118 1.1 jmcneill int8_t *); 119 1.1 jmcneill static int viapcib_smbus_write_byte(void *, i2c_addr_t, uint8_t, 120 1.1 jmcneill int8_t); 121 1.1 jmcneill static int viapcib_smbus_read_word(void *, i2c_addr_t, uint8_t, 122 1.1 jmcneill int16_t *); 123 1.1 jmcneill static int viapcib_smbus_write_word(void *, i2c_addr_t, uint8_t, 124 1.1 jmcneill int16_t); 125 1.1 jmcneill static int viapcib_smbus_block_write(void *, i2c_addr_t, uint8_t, 126 1.1 jmcneill int, void *); 127 1.1 jmcneill static int viapcib_smbus_block_read(void *, i2c_addr_t, uint8_t, 128 1.1 jmcneill int, void *); 129 1.1 jmcneill /* XXX Should be moved to smbus layer */ 130 1.1 jmcneill #define SMB_MAXBLOCKSIZE 32 131 1.1 jmcneill 132 1.10 xtraeme CFATTACH_DECL_NEW(viapcib, sizeof(struct viapcib_softc), 133 1.10 xtraeme viapcib_match, viapcib_attach, NULL, NULL); 134 1.1 jmcneill 135 1.1 jmcneill static int 136 1.10 xtraeme viapcib_match(device_t parent, cfdata_t match, void *opaque) 137 1.1 jmcneill { 138 1.10 xtraeme struct pci_attach_args *pa = opaque; 139 1.1 jmcneill 140 1.1 jmcneill if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH) 141 1.1 jmcneill return 0; 142 1.1 jmcneill 143 1.1 jmcneill switch (PCI_PRODUCT(pa->pa_id)) { 144 1.1 jmcneill case PCI_PRODUCT_VIATECH_VT8235: 145 1.2 xtraeme case PCI_PRODUCT_VIATECH_VT8237: 146 1.12 jmcneill case PCI_PRODUCT_VIATECH_VT8237A_ISA: 147 1.1 jmcneill return 2; /* match above generic pcib(4) */ 148 1.1 jmcneill } 149 1.1 jmcneill 150 1.1 jmcneill return 0; 151 1.1 jmcneill } 152 1.1 jmcneill 153 1.1 jmcneill static void 154 1.10 xtraeme viapcib_attach(device_t parent, device_t self, void *opaque) 155 1.1 jmcneill { 156 1.10 xtraeme struct viapcib_softc *sc = device_private(self); 157 1.10 xtraeme struct pci_attach_args *pa = opaque; 158 1.1 jmcneill pcireg_t addr, val; 159 1.1 jmcneill 160 1.1 jmcneill /* XXX Only the 8235 is supported for now */ 161 1.1 jmcneill sc->sc_iot = pa->pa_iot; 162 1.1 jmcneill addr = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_BASE3); 163 1.1 jmcneill addr &= 0xfff0; 164 1.1 jmcneill if (bus_space_map(sc->sc_iot, addr, 8, 0, &sc->sc_ioh)) { 165 1.1 jmcneill printf(": failed to map SMBus I/O space\n"); 166 1.1 jmcneill addr = 0; 167 1.1 jmcneill goto core_pcib; 168 1.1 jmcneill } 169 1.1 jmcneill 170 1.1 jmcneill val = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_HOST_CONFIG); 171 1.8 joerg if ((val & 0x10000) == 0) { 172 1.1 jmcneill printf(": SMBus is disabled\n"); 173 1.1 jmcneill addr = 0; 174 1.1 jmcneill /* XXX We can enable the SMBus here by writing 1 to 175 1.1 jmcneill * SMB_HOST_CONFIG, but do we want to? 176 1.1 jmcneill */ 177 1.1 jmcneill goto core_pcib; 178 1.1 jmcneill } 179 1.1 jmcneill 180 1.1 jmcneill #ifdef VIAPCIB_DEBUG 181 1.1 jmcneill switch (val & 0x0e) { 182 1.1 jmcneill case 8: 183 1.1 jmcneill printf(": interrupting at irq 9\n"); 184 1.1 jmcneill break; 185 1.1 jmcneill case 0: 186 1.1 jmcneill printf(": interrupting at SMI#\n"); 187 1.1 jmcneill break; 188 1.1 jmcneill default: 189 1.1 jmcneill printf(": interrupt misconfigured\n"); 190 1.1 jmcneill break; 191 1.1 jmcneill } 192 1.1 jmcneill #endif /* !VIAPCIB_DEBUG */ 193 1.1 jmcneill 194 1.1 jmcneill val = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_REVISION); 195 1.8 joerg sc->sc_revision = val >> 16; 196 1.1 jmcneill 197 1.1 jmcneill core_pcib: 198 1.1 jmcneill pcibattach(parent, self, opaque); 199 1.1 jmcneill 200 1.1 jmcneill if (addr != 0) { 201 1.1 jmcneill uint8_t b; 202 1.1 jmcneill 203 1.1 jmcneill printf("%s: SMBus found at 0x%x (revision 0x%x)\n", 204 1.10 xtraeme device_xname(self), addr, sc->sc_revision); 205 1.1 jmcneill 206 1.1 jmcneill /* Disable slave function */ 207 1.1 jmcneill b = viapcib_smbus_read(sc, SMBSLVCNT); 208 1.1 jmcneill viapcib_smbus_write(sc, SMBSLVCNT, b & ~1); 209 1.1 jmcneill 210 1.17 thorpej iic_tag_init(&sc->sc_i2c); 211 1.20 thorpej sc->sc_i2c.ic_cookie = (void *)sc; 212 1.20 thorpej sc->sc_i2c.ic_exec = viapcib_exec; 213 1.1 jmcneill 214 1.20 thorpej iicbus_attach(self, &sc->sc_i2c); 215 1.1 jmcneill } 216 1.1 jmcneill } 217 1.1 jmcneill 218 1.1 jmcneill static int 219 1.1 jmcneill viapcib_wait(struct viapcib_softc *sc) 220 1.1 jmcneill { 221 1.1 jmcneill int rv, timeout; 222 1.14 mrg uint8_t val = 0; 223 1.1 jmcneill 224 1.1 jmcneill timeout = VIAPCIB_SMBUS_TIMEOUT; 225 1.1 jmcneill rv = 0; 226 1.1 jmcneill 227 1.1 jmcneill while (timeout--) { 228 1.1 jmcneill val = viapcib_smbus_read(sc, SMBHSTSTS); 229 1.1 jmcneill if (!(val & SMBHSTSTS_BUSY) && (val & SMBHSTSTS_INTR)) 230 1.1 jmcneill break; 231 1.1 jmcneill DELAY(10); 232 1.1 jmcneill } 233 1.1 jmcneill 234 1.1 jmcneill if (timeout == 0) 235 1.1 jmcneill rv = EBUSY; 236 1.1 jmcneill 237 1.1 jmcneill if ((val & SMBHSTSTS_FAILED) || (val & SMBHSTSTS_COLLISION) || 238 1.1 jmcneill (val & SMBHSTSTS_ERROR)) 239 1.1 jmcneill rv = EIO; 240 1.1 jmcneill 241 1.1 jmcneill viapcib_clear(sc); 242 1.1 jmcneill 243 1.1 jmcneill return rv; 244 1.1 jmcneill } 245 1.1 jmcneill 246 1.1 jmcneill static int 247 1.1 jmcneill viapcib_clear(struct viapcib_softc *sc) 248 1.1 jmcneill { 249 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTSTS, 250 1.1 jmcneill (SMBHSTSTS_FAILED | SMBHSTSTS_COLLISION | SMBHSTSTS_ERROR | 251 1.1 jmcneill SMBHSTSTS_INTR)); 252 1.1 jmcneill DELAY(10); 253 1.1 jmcneill 254 1.1 jmcneill return 0; 255 1.1 jmcneill } 256 1.1 jmcneill 257 1.1 jmcneill static int 258 1.1 jmcneill viapcib_busy(struct viapcib_softc *sc) 259 1.1 jmcneill { 260 1.1 jmcneill uint8_t val; 261 1.1 jmcneill 262 1.1 jmcneill val = viapcib_smbus_read(sc, SMBHSTSTS); 263 1.1 jmcneill 264 1.1 jmcneill return (val & SMBHSTSTS_BUSY); 265 1.1 jmcneill } 266 1.1 jmcneill 267 1.1 jmcneill static int 268 1.1 jmcneill viapcib_exec(void *opaque, i2c_op_t op, i2c_addr_t addr, const void *vcmd, 269 1.6 christos size_t cmdlen, void *vbuf, size_t buflen, int flags) 270 1.1 jmcneill { 271 1.1 jmcneill struct viapcib_softc *sc; 272 1.1 jmcneill uint8_t cmd; 273 1.1 jmcneill int rv = -1; 274 1.1 jmcneill 275 1.1 jmcneill DPRINTF(("viapcib_exec(%p, 0x%x, 0x%x, %p, %d, %p, %d, 0x%x)\n", 276 1.1 jmcneill opaque, op, addr, vcmd, cmdlen, vbuf, buflen, flags)); 277 1.1 jmcneill 278 1.1 jmcneill sc = (struct viapcib_softc *)opaque; 279 1.1 jmcneill 280 1.1 jmcneill if (op != I2C_OP_READ_WITH_STOP && 281 1.1 jmcneill op != I2C_OP_WRITE_WITH_STOP) 282 1.1 jmcneill return -1; 283 1.1 jmcneill 284 1.1 jmcneill if (cmdlen > 0) 285 1.1 jmcneill cmd = *(uint8_t *)(__UNCONST(vcmd)); /* XXX */ 286 1.1 jmcneill 287 1.1 jmcneill switch (cmdlen) { 288 1.1 jmcneill case 0: 289 1.1 jmcneill switch (buflen) { 290 1.1 jmcneill case 0: 291 1.1 jmcneill /* SMBus quick read/write */ 292 1.1 jmcneill if (I2C_OP_READ_P(op)) 293 1.1 jmcneill rv = viapcib_smbus_quick_read(sc, addr); 294 1.1 jmcneill else 295 1.1 jmcneill rv = viapcib_smbus_quick_write(sc, addr); 296 1.1 jmcneill 297 1.1 jmcneill return rv; 298 1.1 jmcneill case 1: 299 1.1 jmcneill /* SMBus send/receive byte */ 300 1.1 jmcneill if (I2C_OP_READ_P(op)) 301 1.1 jmcneill rv = viapcib_smbus_send_byte(sc, addr, 302 1.1 jmcneill *(uint8_t *)vbuf); 303 1.1 jmcneill else 304 1.1 jmcneill rv = viapcib_smbus_receive_byte(sc, addr, 305 1.1 jmcneill (uint8_t *)vbuf); 306 1.1 jmcneill return rv; 307 1.1 jmcneill default: 308 1.1 jmcneill return -1; 309 1.1 jmcneill } 310 1.1 jmcneill case 1: 311 1.1 jmcneill switch (buflen) { 312 1.1 jmcneill case 0: 313 1.1 jmcneill return -1; 314 1.1 jmcneill case 1: 315 1.1 jmcneill /* SMBus read/write byte */ 316 1.1 jmcneill if (I2C_OP_READ_P(op)) 317 1.1 jmcneill rv = viapcib_smbus_read_byte(sc, addr, 318 1.1 jmcneill cmd, (uint8_t *)vbuf); 319 1.1 jmcneill else 320 1.1 jmcneill rv = viapcib_smbus_write_byte(sc, addr, 321 1.1 jmcneill cmd, *(uint8_t *)vbuf); 322 1.1 jmcneill return rv; 323 1.1 jmcneill case 2: 324 1.1 jmcneill /* SMBus read/write word */ 325 1.1 jmcneill if (I2C_OP_READ_P(op)) 326 1.1 jmcneill rv = viapcib_smbus_read_word(sc, addr, 327 1.1 jmcneill cmd, (uint16_t *)vbuf); 328 1.1 jmcneill else 329 1.1 jmcneill rv = viapcib_smbus_write_word(sc, addr, 330 1.1 jmcneill cmd, *(uint16_t *)vbuf); 331 1.1 jmcneill return rv; 332 1.1 jmcneill default: 333 1.1 jmcneill /* SMBus read/write block */ 334 1.1 jmcneill if (I2C_OP_READ_P(op)) 335 1.1 jmcneill rv = viapcib_smbus_block_read(sc, addr, 336 1.1 jmcneill cmd, buflen, vbuf); 337 1.1 jmcneill else 338 1.1 jmcneill rv = viapcib_smbus_block_write(sc, addr, 339 1.1 jmcneill cmd, buflen, vbuf); 340 1.1 jmcneill return rv; 341 1.1 jmcneill } 342 1.1 jmcneill } 343 1.1 jmcneill 344 1.1 jmcneill return -1; /* XXX ??? */ 345 1.1 jmcneill } 346 1.1 jmcneill 347 1.1 jmcneill static int 348 1.1 jmcneill viapcib_smbus_quick_write(void *opaque, i2c_addr_t slave) 349 1.1 jmcneill { 350 1.1 jmcneill struct viapcib_softc *sc; 351 1.1 jmcneill 352 1.1 jmcneill sc = (struct viapcib_softc *)opaque; 353 1.1 jmcneill 354 1.1 jmcneill DPRINTF(("viapcib_smbus_quick_write(%p, 0x%x)\n", opaque, slave)); 355 1.1 jmcneill 356 1.1 jmcneill viapcib_clear(sc); 357 1.1 jmcneill if (viapcib_busy(sc)) 358 1.1 jmcneill return EBUSY; 359 1.1 jmcneill 360 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 361 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK); 362 1.1 jmcneill if (viapcib_wait(sc)) 363 1.1 jmcneill return EBUSY; 364 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START); 365 1.1 jmcneill 366 1.1 jmcneill return viapcib_wait(sc); 367 1.1 jmcneill } 368 1.1 jmcneill 369 1.1 jmcneill static int 370 1.1 jmcneill viapcib_smbus_quick_read(void *opaque, i2c_addr_t slave) 371 1.1 jmcneill { 372 1.1 jmcneill struct viapcib_softc *sc; 373 1.1 jmcneill 374 1.1 jmcneill sc = (struct viapcib_softc *)opaque; 375 1.1 jmcneill 376 1.1 jmcneill DPRINTF(("viapcib_smbus_quick_read(%p, 0x%x)\n", opaque, slave)); 377 1.1 jmcneill 378 1.1 jmcneill viapcib_clear(sc); 379 1.1 jmcneill if (viapcib_busy(sc)) 380 1.1 jmcneill return EBUSY; 381 1.1 jmcneill 382 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 383 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK); 384 1.1 jmcneill if (viapcib_wait(sc)) 385 1.1 jmcneill return EBUSY; 386 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START); 387 1.1 jmcneill 388 1.1 jmcneill return viapcib_wait(sc); 389 1.1 jmcneill } 390 1.1 jmcneill 391 1.1 jmcneill static int 392 1.1 jmcneill viapcib_smbus_send_byte(void *opaque, i2c_addr_t slave, uint8_t byte) 393 1.1 jmcneill { 394 1.1 jmcneill struct viapcib_softc *sc; 395 1.1 jmcneill 396 1.1 jmcneill sc = (struct viapcib_softc *)opaque; 397 1.1 jmcneill 398 1.1 jmcneill DPRINTF(("viapcib_smbus_send_byte(%p, 0x%x, 0x%x)\n", opaque, 399 1.1 jmcneill slave, byte)); 400 1.1 jmcneill 401 1.1 jmcneill viapcib_clear(sc); 402 1.1 jmcneill if (viapcib_busy(sc)) 403 1.1 jmcneill return EBUSY; 404 1.1 jmcneill 405 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 406 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCMD, byte); 407 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV); 408 1.1 jmcneill if (viapcib_wait(sc)) 409 1.1 jmcneill return EBUSY; 410 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, 411 1.1 jmcneill SMBHSTCNT_START | SMBHSTCNT_SENDRECV); 412 1.1 jmcneill 413 1.1 jmcneill return viapcib_wait(sc); 414 1.1 jmcneill } 415 1.1 jmcneill 416 1.1 jmcneill static int 417 1.1 jmcneill viapcib_smbus_receive_byte(void *opaque, i2c_addr_t slave, uint8_t *pbyte) 418 1.1 jmcneill { 419 1.1 jmcneill struct viapcib_softc *sc; 420 1.1 jmcneill int rv; 421 1.1 jmcneill 422 1.1 jmcneill sc = (struct viapcib_softc *)opaque; 423 1.1 jmcneill 424 1.1 jmcneill DPRINTF(("viapcib_smbus_receive_byte(%p, 0x%x, %p)\n", opaque, 425 1.1 jmcneill slave, pbyte)); 426 1.1 jmcneill 427 1.1 jmcneill viapcib_clear(sc); 428 1.1 jmcneill if (viapcib_busy(sc)) 429 1.1 jmcneill return EBUSY; 430 1.1 jmcneill 431 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 432 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV); 433 1.1 jmcneill if (viapcib_wait(sc)) 434 1.1 jmcneill return EBUSY; 435 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, 436 1.1 jmcneill SMBHSTCNT_START | SMBHSTCNT_SENDRECV); 437 1.1 jmcneill 438 1.1 jmcneill rv = viapcib_wait(sc); 439 1.1 jmcneill if (rv == 0) 440 1.1 jmcneill *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0); 441 1.1 jmcneill 442 1.1 jmcneill return rv; 443 1.1 jmcneill } 444 1.1 jmcneill 445 1.1 jmcneill static int 446 1.1 jmcneill viapcib_smbus_write_byte(void *opaque, i2c_addr_t slave, uint8_t cmd, 447 1.1 jmcneill int8_t byte) 448 1.1 jmcneill { 449 1.1 jmcneill struct viapcib_softc *sc; 450 1.1 jmcneill 451 1.1 jmcneill sc = (struct viapcib_softc *)opaque; 452 1.1 jmcneill 453 1.1 jmcneill DPRINTF(("viapcib_smbus_write_byte(%p, 0x%x, 0x%x, 0x%x)\n", opaque, 454 1.1 jmcneill slave, cmd, byte)); 455 1.1 jmcneill 456 1.1 jmcneill viapcib_clear(sc); 457 1.1 jmcneill if (viapcib_busy(sc)) 458 1.1 jmcneill return EBUSY; 459 1.1 jmcneill 460 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 461 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCMD, cmd); 462 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTDAT0, byte); 463 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE); 464 1.1 jmcneill if (viapcib_wait(sc)) 465 1.1 jmcneill return EBUSY; 466 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE); 467 1.1 jmcneill 468 1.1 jmcneill return viapcib_wait(sc); 469 1.1 jmcneill } 470 1.1 jmcneill 471 1.1 jmcneill static int 472 1.1 jmcneill viapcib_smbus_read_byte(void *opaque, i2c_addr_t slave, uint8_t cmd, 473 1.1 jmcneill int8_t *pbyte) 474 1.1 jmcneill { 475 1.1 jmcneill struct viapcib_softc *sc; 476 1.1 jmcneill int rv; 477 1.1 jmcneill 478 1.1 jmcneill sc = (struct viapcib_softc *)opaque; 479 1.1 jmcneill 480 1.1 jmcneill DPRINTF(("viapcib_smbus_read_byte(%p, 0x%x, 0x%x, %p)\n", opaque, 481 1.1 jmcneill slave, cmd, pbyte)); 482 1.1 jmcneill 483 1.1 jmcneill viapcib_clear(sc); 484 1.1 jmcneill if (viapcib_busy(sc)) 485 1.1 jmcneill return EBUSY; 486 1.1 jmcneill 487 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 488 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCMD, cmd); 489 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE); 490 1.1 jmcneill if (viapcib_wait(sc)) 491 1.1 jmcneill return EBUSY; 492 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE); 493 1.1 jmcneill rv = viapcib_wait(sc); 494 1.1 jmcneill if (rv == 0) 495 1.1 jmcneill *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0); 496 1.1 jmcneill 497 1.1 jmcneill return rv; 498 1.1 jmcneill } 499 1.1 jmcneill 500 1.1 jmcneill static int 501 1.1 jmcneill viapcib_smbus_write_word(void *opaque, i2c_addr_t slave, uint8_t cmd, 502 1.1 jmcneill int16_t word) 503 1.1 jmcneill { 504 1.1 jmcneill struct viapcib_softc *sc; 505 1.1 jmcneill 506 1.1 jmcneill sc = (struct viapcib_softc *)opaque; 507 1.1 jmcneill 508 1.1 jmcneill DPRINTF(("viapcib_smbus_write_word(%p, 0x%x, 0x%x, 0x%x)\n", opaque, 509 1.1 jmcneill slave, cmd, word)); 510 1.1 jmcneill 511 1.1 jmcneill viapcib_clear(sc); 512 1.1 jmcneill if (viapcib_busy(sc)) 513 1.1 jmcneill return EBUSY; 514 1.1 jmcneill 515 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 516 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCMD, cmd); 517 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTDAT0, word & 0x00ff); 518 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTDAT1, (word & 0xff00) >> 8); 519 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD); 520 1.1 jmcneill if (viapcib_wait(sc)) 521 1.1 jmcneill return EBUSY; 522 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD); 523 1.1 jmcneill 524 1.1 jmcneill return viapcib_wait(sc); 525 1.1 jmcneill } 526 1.1 jmcneill 527 1.1 jmcneill static int 528 1.1 jmcneill viapcib_smbus_read_word(void *opaque, i2c_addr_t slave, uint8_t cmd, 529 1.1 jmcneill int16_t *pword) 530 1.1 jmcneill { 531 1.1 jmcneill struct viapcib_softc *sc; 532 1.1 jmcneill int rv; 533 1.1 jmcneill int8_t high, low; 534 1.1 jmcneill 535 1.1 jmcneill sc = (struct viapcib_softc *)opaque; 536 1.1 jmcneill 537 1.1 jmcneill DPRINTF(("viapcib_smbus_read_word(%p, 0x%x, 0x%x, %p)\n", opaque, 538 1.1 jmcneill slave, cmd, pword)); 539 1.1 jmcneill 540 1.1 jmcneill viapcib_clear(sc); 541 1.1 jmcneill if (viapcib_busy(sc)) 542 1.1 jmcneill return EBUSY; 543 1.1 jmcneill 544 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 545 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCMD, cmd); 546 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD); 547 1.1 jmcneill if (viapcib_wait(sc)) 548 1.1 jmcneill return EBUSY; 549 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD); 550 1.1 jmcneill 551 1.1 jmcneill rv = viapcib_wait(sc); 552 1.1 jmcneill if (rv == 0) { 553 1.1 jmcneill low = viapcib_smbus_read(sc, SMBHSTDAT0); 554 1.1 jmcneill high = viapcib_smbus_read(sc, SMBHSTDAT1); 555 1.1 jmcneill *pword = ((high & 0xff) << 8) | (low & 0xff); 556 1.1 jmcneill } 557 1.1 jmcneill 558 1.1 jmcneill return rv; 559 1.1 jmcneill } 560 1.1 jmcneill 561 1.1 jmcneill static int 562 1.1 jmcneill viapcib_smbus_block_write(void *opaque, i2c_addr_t slave, uint8_t cmd, 563 1.1 jmcneill int cnt, void *data) 564 1.1 jmcneill { 565 1.1 jmcneill struct viapcib_softc *sc; 566 1.1 jmcneill int8_t *buf; 567 1.1 jmcneill int remain, len, i; 568 1.1 jmcneill int rv; 569 1.1 jmcneill 570 1.1 jmcneill sc = (struct viapcib_softc *)opaque; 571 1.1 jmcneill buf = (int8_t *)data; 572 1.1 jmcneill rv = 0; 573 1.1 jmcneill 574 1.1 jmcneill DPRINTF(("viapcib_smbus_block_write(%p, 0x%x, 0x%x, %d, %p)\n", 575 1.1 jmcneill opaque, slave, cmd, cnt, data)); 576 1.1 jmcneill 577 1.1 jmcneill viapcib_clear(sc); 578 1.1 jmcneill if (viapcib_busy(sc)) 579 1.1 jmcneill return EBUSY; 580 1.1 jmcneill 581 1.1 jmcneill remain = cnt; 582 1.1 jmcneill while (remain) { 583 1.16 riastrad len = uimin(remain, SMB_MAXBLOCKSIZE); 584 1.1 jmcneill 585 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 586 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCMD, cmd); 587 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTDAT0, len); 588 1.1 jmcneill i = viapcib_smbus_read(sc, SMBHSTCNT); 589 1.1 jmcneill /* XXX FreeBSD does this, but it looks wrong */ 590 1.1 jmcneill for (i = 0; i < len; i++) { 591 1.1 jmcneill viapcib_smbus_write(sc, SMBBLKDAT, 592 1.1 jmcneill buf[cnt - remain + i]); 593 1.1 jmcneill } 594 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK); 595 1.1 jmcneill if (viapcib_wait(sc)) 596 1.1 jmcneill return EBUSY; 597 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, 598 1.1 jmcneill SMBHSTCNT_START | SMBHSTCNT_BLOCK); 599 1.1 jmcneill if (viapcib_wait(sc)) 600 1.1 jmcneill return EBUSY; 601 1.1 jmcneill 602 1.1 jmcneill remain -= len; 603 1.1 jmcneill } 604 1.1 jmcneill 605 1.1 jmcneill return rv; 606 1.1 jmcneill } 607 1.1 jmcneill 608 1.1 jmcneill static int 609 1.1 jmcneill viapcib_smbus_block_read(void *opaque, i2c_addr_t slave, uint8_t cmd, 610 1.1 jmcneill int cnt, void *data) 611 1.1 jmcneill { 612 1.1 jmcneill struct viapcib_softc *sc; 613 1.1 jmcneill int8_t *buf; 614 1.1 jmcneill int remain, len, i; 615 1.1 jmcneill int rv; 616 1.1 jmcneill 617 1.1 jmcneill sc = (struct viapcib_softc *)opaque; 618 1.1 jmcneill buf = (int8_t *)data; 619 1.1 jmcneill rv = 0; 620 1.1 jmcneill 621 1.1 jmcneill DPRINTF(("viapcib_smbus_block_read(%p, 0x%x, 0x%x, %d, %p)\n", 622 1.1 jmcneill opaque, slave, cmd, cnt, data)); 623 1.1 jmcneill 624 1.1 jmcneill viapcib_clear(sc); 625 1.1 jmcneill if (viapcib_busy(sc)) 626 1.1 jmcneill return EBUSY; 627 1.1 jmcneill 628 1.1 jmcneill remain = cnt; 629 1.1 jmcneill while (remain) { 630 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 631 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCMD, cmd); 632 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK); 633 1.1 jmcneill if (viapcib_wait(sc)) 634 1.1 jmcneill return EBUSY; 635 1.1 jmcneill viapcib_smbus_write(sc, SMBHSTCNT, 636 1.1 jmcneill SMBHSTCNT_START | SMBHSTCNT_BLOCK); 637 1.1 jmcneill if (viapcib_wait(sc)) 638 1.1 jmcneill return EBUSY; 639 1.1 jmcneill 640 1.1 jmcneill len = viapcib_smbus_read(sc, SMBHSTDAT0); 641 1.1 jmcneill i = viapcib_smbus_read(sc, SMBHSTCNT); 642 1.1 jmcneill 643 1.16 riastrad len = uimin(len, remain); 644 1.1 jmcneill 645 1.1 jmcneill /* FreeBSD does this too... */ 646 1.1 jmcneill for (i = 0; i < len; i++) { 647 1.1 jmcneill buf[cnt - remain + i] = 648 1.1 jmcneill viapcib_smbus_read(sc, SMBBLKDAT); 649 1.1 jmcneill } 650 1.1 jmcneill 651 1.1 jmcneill remain -= len; 652 1.1 jmcneill } 653 1.1 jmcneill 654 1.1 jmcneill return rv; 655 1.1 jmcneill } 656