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