1 /* $NetBSD: viapcib.c,v 1.11 2008/07/20 16:59:53 martin 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.11 2008/07/20 16:59:53 martin 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/proc.h> 65 #include <sys/simplelock.h> 66 #include <sys/bus.h> 67 68 #include <dev/pci/pcireg.h> 69 #include <dev/pci/pcivar.h> 70 #include <dev/pci/pcidevs.h> 71 72 #include <dev/i2c/i2cvar.h> 73 74 #include <i386/pci/viapcibreg.h> 75 #include <x86/pci/pcibvar.h> 76 77 /*#define VIAPCIB_DEBUG*/ 78 79 #ifdef VIAPCIB_DEBUG 80 #define DPRINTF(x) printf x 81 #else 82 #define DPRINTF(x) 83 #endif 84 85 struct viapcib_softc { 86 /* we call pcibattach(), which assumes softc starts like this: */ 87 struct pcib_softc sc_pcib; 88 89 bus_space_tag_t sc_iot; 90 bus_space_handle_t sc_ioh; 91 struct i2c_controller sc_i2c; 92 93 int sc_revision; 94 95 struct simplelock sc_lock; 96 }; 97 98 static int viapcib_match(device_t, cfdata_t, void *); 99 static void viapcib_attach(device_t, device_t, void *); 100 101 static int viapcib_clear(struct viapcib_softc *); 102 static int viapcib_busy(struct viapcib_softc *); 103 104 #define viapcib_smbus_read(sc, o) \ 105 bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (o)) 106 #define viapcib_smbus_write(sc, o, v) \ 107 bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (o), (v)) 108 109 #define VIAPCIB_SMBUS_TIMEOUT 10000 110 111 static int viapcib_acquire_bus(void *, int); 112 static void viapcib_release_bus(void *, int); 113 static int viapcib_exec(void *, i2c_op_t, i2c_addr_t, const void *, 114 size_t, void *, size_t, int); 115 116 /* SMBus operations */ 117 static int viapcib_smbus_quick_write(void *, i2c_addr_t); 118 static int viapcib_smbus_quick_read(void *, i2c_addr_t); 119 static int viapcib_smbus_send_byte(void *, i2c_addr_t, uint8_t); 120 static int viapcib_smbus_receive_byte(void *, i2c_addr_t, 121 uint8_t *); 122 static int viapcib_smbus_read_byte(void *, i2c_addr_t, uint8_t, 123 int8_t *); 124 static int viapcib_smbus_write_byte(void *, i2c_addr_t, uint8_t, 125 int8_t); 126 static int viapcib_smbus_read_word(void *, i2c_addr_t, uint8_t, 127 int16_t *); 128 static int viapcib_smbus_write_word(void *, i2c_addr_t, uint8_t, 129 int16_t); 130 static int viapcib_smbus_block_write(void *, i2c_addr_t, uint8_t, 131 int, void *); 132 static int viapcib_smbus_block_read(void *, i2c_addr_t, uint8_t, 133 int, void *); 134 /* XXX Should be moved to smbus layer */ 135 #define SMB_MAXBLOCKSIZE 32 136 137 CFATTACH_DECL_NEW(viapcib, sizeof(struct viapcib_softc), 138 viapcib_match, viapcib_attach, NULL, NULL); 139 140 static int 141 viapcib_match(device_t parent, cfdata_t match, void *opaque) 142 { 143 struct pci_attach_args *pa = opaque; 144 145 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH) 146 return 0; 147 148 switch (PCI_PRODUCT(pa->pa_id)) { 149 case PCI_PRODUCT_VIATECH_VT8235: 150 case PCI_PRODUCT_VIATECH_VT8237: 151 return 2; /* match above generic pcib(4) */ 152 } 153 154 return 0; 155 } 156 157 static void 158 viapcib_attach(device_t parent, device_t self, void *opaque) 159 { 160 struct viapcib_softc *sc = device_private(self); 161 struct pci_attach_args *pa = opaque; 162 pcireg_t addr, val; 163 164 /* XXX Only the 8235 is supported for now */ 165 sc->sc_iot = pa->pa_iot; 166 addr = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_BASE3); 167 addr &= 0xfff0; 168 if (bus_space_map(sc->sc_iot, addr, 8, 0, &sc->sc_ioh)) { 169 printf(": failed to map SMBus I/O space\n"); 170 addr = 0; 171 goto core_pcib; 172 } 173 174 simple_lock_init(&sc->sc_lock); 175 176 val = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_HOST_CONFIG); 177 if ((val & 0x10000) == 0) { 178 printf(": SMBus is disabled\n"); 179 addr = 0; 180 /* XXX We can enable the SMBus here by writing 1 to 181 * SMB_HOST_CONFIG, but do we want to? 182 */ 183 goto core_pcib; 184 } 185 186 #ifdef VIAPCIB_DEBUG 187 switch (val & 0x0e) { 188 case 8: 189 printf(": interrupting at irq 9\n"); 190 break; 191 case 0: 192 printf(": interrupting at SMI#\n"); 193 break; 194 default: 195 printf(": interrupt misconfigured\n"); 196 break; 197 } 198 #endif /* !VIAPCIB_DEBUG */ 199 200 val = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_REVISION); 201 sc->sc_revision = val >> 16; 202 203 core_pcib: 204 pcibattach(parent, self, opaque); 205 206 if (addr != 0) { 207 struct i2cbus_attach_args iba; 208 uint8_t b; 209 210 printf("%s: SMBus found at 0x%x (revision 0x%x)\n", 211 device_xname(self), addr, sc->sc_revision); 212 213 /* Disable slave function */ 214 b = viapcib_smbus_read(sc, SMBSLVCNT); 215 viapcib_smbus_write(sc, SMBSLVCNT, b & ~1); 216 217 memset(&sc->sc_i2c, 0, sizeof(sc->sc_i2c)); 218 #ifdef I2C_TYPE_SMBUS 219 iba.iba_type = I2C_TYPE_SMBUS; 220 #endif 221 iba.iba_tag = &sc->sc_i2c; 222 iba.iba_tag->ic_cookie = (void *)sc; 223 iba.iba_tag->ic_acquire_bus = viapcib_acquire_bus; 224 iba.iba_tag->ic_release_bus = viapcib_release_bus; 225 iba.iba_tag->ic_exec = viapcib_exec; 226 227 config_found_ia(self, "i2cbus", &iba, iicbus_print); 228 } 229 } 230 231 static int 232 viapcib_wait(struct viapcib_softc *sc) 233 { 234 int rv, timeout; 235 uint8_t val; 236 237 timeout = VIAPCIB_SMBUS_TIMEOUT; 238 rv = 0; 239 240 while (timeout--) { 241 val = viapcib_smbus_read(sc, SMBHSTSTS); 242 if (!(val & SMBHSTSTS_BUSY) && (val & SMBHSTSTS_INTR)) 243 break; 244 DELAY(10); 245 } 246 247 if (timeout == 0) 248 rv = EBUSY; 249 250 if ((val & SMBHSTSTS_FAILED) || (val & SMBHSTSTS_COLLISION) || 251 (val & SMBHSTSTS_ERROR)) 252 rv = EIO; 253 254 viapcib_clear(sc); 255 256 return rv; 257 } 258 259 static int 260 viapcib_clear(struct viapcib_softc *sc) 261 { 262 viapcib_smbus_write(sc, SMBHSTSTS, 263 (SMBHSTSTS_FAILED | SMBHSTSTS_COLLISION | SMBHSTSTS_ERROR | 264 SMBHSTSTS_INTR)); 265 DELAY(10); 266 267 return 0; 268 } 269 270 static int 271 viapcib_busy(struct viapcib_softc *sc) 272 { 273 uint8_t val; 274 275 val = viapcib_smbus_read(sc, SMBHSTSTS); 276 277 return (val & SMBHSTSTS_BUSY); 278 } 279 280 static int 281 viapcib_acquire_bus(void *opaque, int flags) 282 { 283 struct viapcib_softc *sc; 284 285 DPRINTF(("viapcib_i2c_acquire_bus(%p, 0x%x)\n", opaque, flags)); 286 287 sc = (struct viapcib_softc *)opaque; 288 289 simple_lock(&sc->sc_lock); 290 291 return 0; 292 } 293 294 static void 295 viapcib_release_bus(void *opaque, int flags) 296 { 297 struct viapcib_softc *sc; 298 299 DPRINTF(("viapcib_i2c_release_bus(%p, 0x%x)\n", opaque, flags)); 300 301 sc = (struct viapcib_softc *)opaque; 302 303 simple_unlock(&sc->sc_lock); 304 305 return; 306 } 307 308 static int 309 viapcib_exec(void *opaque, i2c_op_t op, i2c_addr_t addr, const void *vcmd, 310 size_t cmdlen, void *vbuf, size_t buflen, int flags) 311 { 312 struct viapcib_softc *sc; 313 uint8_t cmd; 314 int rv = -1; 315 316 DPRINTF(("viapcib_exec(%p, 0x%x, 0x%x, %p, %d, %p, %d, 0x%x)\n", 317 opaque, op, addr, vcmd, cmdlen, vbuf, buflen, flags)); 318 319 sc = (struct viapcib_softc *)opaque; 320 321 if (op != I2C_OP_READ_WITH_STOP && 322 op != I2C_OP_WRITE_WITH_STOP) 323 return -1; 324 325 if (cmdlen > 0) 326 cmd = *(uint8_t *)(__UNCONST(vcmd)); /* XXX */ 327 328 switch (cmdlen) { 329 case 0: 330 switch (buflen) { 331 case 0: 332 /* SMBus quick read/write */ 333 if (I2C_OP_READ_P(op)) 334 rv = viapcib_smbus_quick_read(sc, addr); 335 else 336 rv = viapcib_smbus_quick_write(sc, addr); 337 338 return rv; 339 case 1: 340 /* SMBus send/receive byte */ 341 if (I2C_OP_READ_P(op)) 342 rv = viapcib_smbus_send_byte(sc, addr, 343 *(uint8_t *)vbuf); 344 else 345 rv = viapcib_smbus_receive_byte(sc, addr, 346 (uint8_t *)vbuf); 347 return rv; 348 default: 349 return -1; 350 } 351 case 1: 352 switch (buflen) { 353 case 0: 354 return -1; 355 case 1: 356 /* SMBus read/write byte */ 357 if (I2C_OP_READ_P(op)) 358 rv = viapcib_smbus_read_byte(sc, addr, 359 cmd, (uint8_t *)vbuf); 360 else 361 rv = viapcib_smbus_write_byte(sc, addr, 362 cmd, *(uint8_t *)vbuf); 363 return rv; 364 case 2: 365 /* SMBus read/write word */ 366 if (I2C_OP_READ_P(op)) 367 rv = viapcib_smbus_read_word(sc, addr, 368 cmd, (uint16_t *)vbuf); 369 else 370 rv = viapcib_smbus_write_word(sc, addr, 371 cmd, *(uint16_t *)vbuf); 372 return rv; 373 default: 374 /* SMBus read/write block */ 375 if (I2C_OP_READ_P(op)) 376 rv = viapcib_smbus_block_read(sc, addr, 377 cmd, buflen, vbuf); 378 else 379 rv = viapcib_smbus_block_write(sc, addr, 380 cmd, buflen, vbuf); 381 return rv; 382 } 383 } 384 385 return -1; /* XXX ??? */ 386 } 387 388 static int 389 viapcib_smbus_quick_write(void *opaque, i2c_addr_t slave) 390 { 391 struct viapcib_softc *sc; 392 393 sc = (struct viapcib_softc *)opaque; 394 395 DPRINTF(("viapcib_smbus_quick_write(%p, 0x%x)\n", opaque, slave)); 396 397 viapcib_clear(sc); 398 if (viapcib_busy(sc)) 399 return EBUSY; 400 401 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 402 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK); 403 if (viapcib_wait(sc)) 404 return EBUSY; 405 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START); 406 407 return viapcib_wait(sc); 408 } 409 410 static int 411 viapcib_smbus_quick_read(void *opaque, i2c_addr_t slave) 412 { 413 struct viapcib_softc *sc; 414 415 sc = (struct viapcib_softc *)opaque; 416 417 DPRINTF(("viapcib_smbus_quick_read(%p, 0x%x)\n", opaque, slave)); 418 419 viapcib_clear(sc); 420 if (viapcib_busy(sc)) 421 return EBUSY; 422 423 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 424 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK); 425 if (viapcib_wait(sc)) 426 return EBUSY; 427 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START); 428 429 return viapcib_wait(sc); 430 } 431 432 static int 433 viapcib_smbus_send_byte(void *opaque, i2c_addr_t slave, uint8_t byte) 434 { 435 struct viapcib_softc *sc; 436 437 sc = (struct viapcib_softc *)opaque; 438 439 DPRINTF(("viapcib_smbus_send_byte(%p, 0x%x, 0x%x)\n", opaque, 440 slave, byte)); 441 442 viapcib_clear(sc); 443 if (viapcib_busy(sc)) 444 return EBUSY; 445 446 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 447 viapcib_smbus_write(sc, SMBHSTCMD, byte); 448 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV); 449 if (viapcib_wait(sc)) 450 return EBUSY; 451 viapcib_smbus_write(sc, SMBHSTCNT, 452 SMBHSTCNT_START | SMBHSTCNT_SENDRECV); 453 454 return viapcib_wait(sc); 455 } 456 457 static int 458 viapcib_smbus_receive_byte(void *opaque, i2c_addr_t slave, uint8_t *pbyte) 459 { 460 struct viapcib_softc *sc; 461 int rv; 462 463 sc = (struct viapcib_softc *)opaque; 464 465 DPRINTF(("viapcib_smbus_receive_byte(%p, 0x%x, %p)\n", opaque, 466 slave, pbyte)); 467 468 viapcib_clear(sc); 469 if (viapcib_busy(sc)) 470 return EBUSY; 471 472 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 473 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV); 474 if (viapcib_wait(sc)) 475 return EBUSY; 476 viapcib_smbus_write(sc, SMBHSTCNT, 477 SMBHSTCNT_START | SMBHSTCNT_SENDRECV); 478 479 rv = viapcib_wait(sc); 480 if (rv == 0) 481 *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0); 482 483 return rv; 484 } 485 486 static int 487 viapcib_smbus_write_byte(void *opaque, i2c_addr_t slave, uint8_t cmd, 488 int8_t byte) 489 { 490 struct viapcib_softc *sc; 491 492 sc = (struct viapcib_softc *)opaque; 493 494 DPRINTF(("viapcib_smbus_write_byte(%p, 0x%x, 0x%x, 0x%x)\n", opaque, 495 slave, cmd, byte)); 496 497 viapcib_clear(sc); 498 if (viapcib_busy(sc)) 499 return EBUSY; 500 501 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 502 viapcib_smbus_write(sc, SMBHSTCMD, cmd); 503 viapcib_smbus_write(sc, SMBHSTDAT0, byte); 504 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE); 505 if (viapcib_wait(sc)) 506 return EBUSY; 507 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE); 508 509 return viapcib_wait(sc); 510 } 511 512 static int 513 viapcib_smbus_read_byte(void *opaque, i2c_addr_t slave, uint8_t cmd, 514 int8_t *pbyte) 515 { 516 struct viapcib_softc *sc; 517 int rv; 518 519 sc = (struct viapcib_softc *)opaque; 520 521 DPRINTF(("viapcib_smbus_read_byte(%p, 0x%x, 0x%x, %p)\n", opaque, 522 slave, cmd, pbyte)); 523 524 viapcib_clear(sc); 525 if (viapcib_busy(sc)) 526 return EBUSY; 527 528 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 529 viapcib_smbus_write(sc, SMBHSTCMD, cmd); 530 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE); 531 if (viapcib_wait(sc)) 532 return EBUSY; 533 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE); 534 rv = viapcib_wait(sc); 535 if (rv == 0) 536 *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0); 537 538 return rv; 539 } 540 541 static int 542 viapcib_smbus_write_word(void *opaque, i2c_addr_t slave, uint8_t cmd, 543 int16_t word) 544 { 545 struct viapcib_softc *sc; 546 547 sc = (struct viapcib_softc *)opaque; 548 549 DPRINTF(("viapcib_smbus_write_word(%p, 0x%x, 0x%x, 0x%x)\n", opaque, 550 slave, cmd, word)); 551 552 viapcib_clear(sc); 553 if (viapcib_busy(sc)) 554 return EBUSY; 555 556 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 557 viapcib_smbus_write(sc, SMBHSTCMD, cmd); 558 viapcib_smbus_write(sc, SMBHSTDAT0, word & 0x00ff); 559 viapcib_smbus_write(sc, SMBHSTDAT1, (word & 0xff00) >> 8); 560 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD); 561 if (viapcib_wait(sc)) 562 return EBUSY; 563 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD); 564 565 return viapcib_wait(sc); 566 } 567 568 static int 569 viapcib_smbus_read_word(void *opaque, i2c_addr_t slave, uint8_t cmd, 570 int16_t *pword) 571 { 572 struct viapcib_softc *sc; 573 int rv; 574 int8_t high, low; 575 576 sc = (struct viapcib_softc *)opaque; 577 578 DPRINTF(("viapcib_smbus_read_word(%p, 0x%x, 0x%x, %p)\n", opaque, 579 slave, cmd, pword)); 580 581 viapcib_clear(sc); 582 if (viapcib_busy(sc)) 583 return EBUSY; 584 585 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 586 viapcib_smbus_write(sc, SMBHSTCMD, cmd); 587 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD); 588 if (viapcib_wait(sc)) 589 return EBUSY; 590 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD); 591 592 rv = viapcib_wait(sc); 593 if (rv == 0) { 594 low = viapcib_smbus_read(sc, SMBHSTDAT0); 595 high = viapcib_smbus_read(sc, SMBHSTDAT1); 596 *pword = ((high & 0xff) << 8) | (low & 0xff); 597 } 598 599 return rv; 600 } 601 602 static int 603 viapcib_smbus_block_write(void *opaque, i2c_addr_t slave, uint8_t cmd, 604 int cnt, void *data) 605 { 606 struct viapcib_softc *sc; 607 int8_t *buf; 608 int remain, len, i; 609 int rv; 610 611 sc = (struct viapcib_softc *)opaque; 612 buf = (int8_t *)data; 613 rv = 0; 614 615 DPRINTF(("viapcib_smbus_block_write(%p, 0x%x, 0x%x, %d, %p)\n", 616 opaque, slave, cmd, cnt, data)); 617 618 viapcib_clear(sc); 619 if (viapcib_busy(sc)) 620 return EBUSY; 621 622 remain = cnt; 623 while (remain) { 624 len = min(remain, SMB_MAXBLOCKSIZE); 625 626 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 627 viapcib_smbus_write(sc, SMBHSTCMD, cmd); 628 viapcib_smbus_write(sc, SMBHSTDAT0, len); 629 i = viapcib_smbus_read(sc, SMBHSTCNT); 630 /* XXX FreeBSD does this, but it looks wrong */ 631 for (i = 0; i < len; i++) { 632 viapcib_smbus_write(sc, SMBBLKDAT, 633 buf[cnt - remain + i]); 634 } 635 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK); 636 if (viapcib_wait(sc)) 637 return EBUSY; 638 viapcib_smbus_write(sc, SMBHSTCNT, 639 SMBHSTCNT_START | SMBHSTCNT_BLOCK); 640 if (viapcib_wait(sc)) 641 return EBUSY; 642 643 remain -= len; 644 } 645 646 return rv; 647 } 648 649 static int 650 viapcib_smbus_block_read(void *opaque, i2c_addr_t slave, uint8_t cmd, 651 int cnt, void *data) 652 { 653 struct viapcib_softc *sc; 654 int8_t *buf; 655 int remain, len, i; 656 int rv; 657 658 sc = (struct viapcib_softc *)opaque; 659 buf = (int8_t *)data; 660 rv = 0; 661 662 DPRINTF(("viapcib_smbus_block_read(%p, 0x%x, 0x%x, %d, %p)\n", 663 opaque, slave, cmd, cnt, data)); 664 665 viapcib_clear(sc); 666 if (viapcib_busy(sc)) 667 return EBUSY; 668 669 remain = cnt; 670 while (remain) { 671 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 672 viapcib_smbus_write(sc, SMBHSTCMD, cmd); 673 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK); 674 if (viapcib_wait(sc)) 675 return EBUSY; 676 viapcib_smbus_write(sc, SMBHSTCNT, 677 SMBHSTCNT_START | SMBHSTCNT_BLOCK); 678 if (viapcib_wait(sc)) 679 return EBUSY; 680 681 len = viapcib_smbus_read(sc, SMBHSTDAT0); 682 i = viapcib_smbus_read(sc, SMBHSTCNT); 683 684 len = min(len, remain); 685 686 /* FreeBSD does this too... */ 687 for (i = 0; i < len; i++) { 688 buf[cnt - remain + i] = 689 viapcib_smbus_read(sc, SMBBLKDAT); 690 } 691 692 remain -= len; 693 } 694 695 return rv; 696 } 697