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