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