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