1 /* $NetBSD: viapcib.c,v 1.15 2016/02/14 19:54:20 chs 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.15 2016/02/14 19:54:20 chs 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 kmutex_t sc_lock; 95 }; 96 97 static int viapcib_match(device_t, cfdata_t, void *); 98 static void viapcib_attach(device_t, device_t, void *); 99 100 static int viapcib_clear(struct viapcib_softc *); 101 static int viapcib_busy(struct viapcib_softc *); 102 103 #define viapcib_smbus_read(sc, o) \ 104 bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (o)) 105 #define viapcib_smbus_write(sc, o, v) \ 106 bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (o), (v)) 107 108 #define VIAPCIB_SMBUS_TIMEOUT 10000 109 110 static int viapcib_acquire_bus(void *, int); 111 static void viapcib_release_bus(void *, int); 112 static int viapcib_exec(void *, i2c_op_t, i2c_addr_t, const void *, 113 size_t, void *, size_t, int); 114 115 /* SMBus operations */ 116 static int viapcib_smbus_quick_write(void *, i2c_addr_t); 117 static int viapcib_smbus_quick_read(void *, i2c_addr_t); 118 static int viapcib_smbus_send_byte(void *, i2c_addr_t, uint8_t); 119 static int viapcib_smbus_receive_byte(void *, i2c_addr_t, 120 uint8_t *); 121 static int viapcib_smbus_read_byte(void *, i2c_addr_t, uint8_t, 122 int8_t *); 123 static int viapcib_smbus_write_byte(void *, i2c_addr_t, uint8_t, 124 int8_t); 125 static int viapcib_smbus_read_word(void *, i2c_addr_t, uint8_t, 126 int16_t *); 127 static int viapcib_smbus_write_word(void *, i2c_addr_t, uint8_t, 128 int16_t); 129 static int viapcib_smbus_block_write(void *, i2c_addr_t, uint8_t, 130 int, void *); 131 static int viapcib_smbus_block_read(void *, i2c_addr_t, uint8_t, 132 int, void *); 133 /* XXX Should be moved to smbus layer */ 134 #define SMB_MAXBLOCKSIZE 32 135 136 CFATTACH_DECL_NEW(viapcib, sizeof(struct viapcib_softc), 137 viapcib_match, viapcib_attach, NULL, NULL); 138 139 static int 140 viapcib_match(device_t parent, cfdata_t match, void *opaque) 141 { 142 struct pci_attach_args *pa = opaque; 143 144 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH) 145 return 0; 146 147 switch (PCI_PRODUCT(pa->pa_id)) { 148 case PCI_PRODUCT_VIATECH_VT8235: 149 case PCI_PRODUCT_VIATECH_VT8237: 150 case PCI_PRODUCT_VIATECH_VT8237A_ISA: 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 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 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 memset(&iba, 0, sizeof(iba)); 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 = 0; 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 = (struct viapcib_softc *)opaque; 285 286 DPRINTF(("viapcib_i2c_acquire_bus(%p, 0x%x)\n", opaque, flags)); 287 mutex_enter(&sc->sc_lock); 288 289 return 0; 290 } 291 292 static void 293 viapcib_release_bus(void *opaque, int flags) 294 { 295 struct viapcib_softc *sc = (struct viapcib_softc *)opaque; 296 297 mutex_exit(&sc->sc_lock); 298 DPRINTF(("viapcib_i2c_release_bus(%p, 0x%x)\n", opaque, flags)); 299 } 300 301 static int 302 viapcib_exec(void *opaque, i2c_op_t op, i2c_addr_t addr, const void *vcmd, 303 size_t cmdlen, void *vbuf, size_t buflen, int flags) 304 { 305 struct viapcib_softc *sc; 306 uint8_t cmd; 307 int rv = -1; 308 309 DPRINTF(("viapcib_exec(%p, 0x%x, 0x%x, %p, %d, %p, %d, 0x%x)\n", 310 opaque, op, addr, vcmd, cmdlen, vbuf, buflen, flags)); 311 312 sc = (struct viapcib_softc *)opaque; 313 314 if (op != I2C_OP_READ_WITH_STOP && 315 op != I2C_OP_WRITE_WITH_STOP) 316 return -1; 317 318 if (cmdlen > 0) 319 cmd = *(uint8_t *)(__UNCONST(vcmd)); /* XXX */ 320 321 switch (cmdlen) { 322 case 0: 323 switch (buflen) { 324 case 0: 325 /* SMBus quick read/write */ 326 if (I2C_OP_READ_P(op)) 327 rv = viapcib_smbus_quick_read(sc, addr); 328 else 329 rv = viapcib_smbus_quick_write(sc, addr); 330 331 return rv; 332 case 1: 333 /* SMBus send/receive byte */ 334 if (I2C_OP_READ_P(op)) 335 rv = viapcib_smbus_send_byte(sc, addr, 336 *(uint8_t *)vbuf); 337 else 338 rv = viapcib_smbus_receive_byte(sc, addr, 339 (uint8_t *)vbuf); 340 return rv; 341 default: 342 return -1; 343 } 344 case 1: 345 switch (buflen) { 346 case 0: 347 return -1; 348 case 1: 349 /* SMBus read/write byte */ 350 if (I2C_OP_READ_P(op)) 351 rv = viapcib_smbus_read_byte(sc, addr, 352 cmd, (uint8_t *)vbuf); 353 else 354 rv = viapcib_smbus_write_byte(sc, addr, 355 cmd, *(uint8_t *)vbuf); 356 return rv; 357 case 2: 358 /* SMBus read/write word */ 359 if (I2C_OP_READ_P(op)) 360 rv = viapcib_smbus_read_word(sc, addr, 361 cmd, (uint16_t *)vbuf); 362 else 363 rv = viapcib_smbus_write_word(sc, addr, 364 cmd, *(uint16_t *)vbuf); 365 return rv; 366 default: 367 /* SMBus read/write block */ 368 if (I2C_OP_READ_P(op)) 369 rv = viapcib_smbus_block_read(sc, addr, 370 cmd, buflen, vbuf); 371 else 372 rv = viapcib_smbus_block_write(sc, addr, 373 cmd, buflen, vbuf); 374 return rv; 375 } 376 } 377 378 return -1; /* XXX ??? */ 379 } 380 381 static int 382 viapcib_smbus_quick_write(void *opaque, i2c_addr_t slave) 383 { 384 struct viapcib_softc *sc; 385 386 sc = (struct viapcib_softc *)opaque; 387 388 DPRINTF(("viapcib_smbus_quick_write(%p, 0x%x)\n", opaque, slave)); 389 390 viapcib_clear(sc); 391 if (viapcib_busy(sc)) 392 return EBUSY; 393 394 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 395 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK); 396 if (viapcib_wait(sc)) 397 return EBUSY; 398 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START); 399 400 return viapcib_wait(sc); 401 } 402 403 static int 404 viapcib_smbus_quick_read(void *opaque, i2c_addr_t slave) 405 { 406 struct viapcib_softc *sc; 407 408 sc = (struct viapcib_softc *)opaque; 409 410 DPRINTF(("viapcib_smbus_quick_read(%p, 0x%x)\n", opaque, slave)); 411 412 viapcib_clear(sc); 413 if (viapcib_busy(sc)) 414 return EBUSY; 415 416 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 417 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK); 418 if (viapcib_wait(sc)) 419 return EBUSY; 420 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START); 421 422 return viapcib_wait(sc); 423 } 424 425 static int 426 viapcib_smbus_send_byte(void *opaque, i2c_addr_t slave, uint8_t byte) 427 { 428 struct viapcib_softc *sc; 429 430 sc = (struct viapcib_softc *)opaque; 431 432 DPRINTF(("viapcib_smbus_send_byte(%p, 0x%x, 0x%x)\n", opaque, 433 slave, byte)); 434 435 viapcib_clear(sc); 436 if (viapcib_busy(sc)) 437 return EBUSY; 438 439 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 440 viapcib_smbus_write(sc, SMBHSTCMD, byte); 441 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV); 442 if (viapcib_wait(sc)) 443 return EBUSY; 444 viapcib_smbus_write(sc, SMBHSTCNT, 445 SMBHSTCNT_START | SMBHSTCNT_SENDRECV); 446 447 return viapcib_wait(sc); 448 } 449 450 static int 451 viapcib_smbus_receive_byte(void *opaque, i2c_addr_t slave, uint8_t *pbyte) 452 { 453 struct viapcib_softc *sc; 454 int rv; 455 456 sc = (struct viapcib_softc *)opaque; 457 458 DPRINTF(("viapcib_smbus_receive_byte(%p, 0x%x, %p)\n", opaque, 459 slave, pbyte)); 460 461 viapcib_clear(sc); 462 if (viapcib_busy(sc)) 463 return EBUSY; 464 465 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 466 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV); 467 if (viapcib_wait(sc)) 468 return EBUSY; 469 viapcib_smbus_write(sc, SMBHSTCNT, 470 SMBHSTCNT_START | SMBHSTCNT_SENDRECV); 471 472 rv = viapcib_wait(sc); 473 if (rv == 0) 474 *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0); 475 476 return rv; 477 } 478 479 static int 480 viapcib_smbus_write_byte(void *opaque, i2c_addr_t slave, uint8_t cmd, 481 int8_t byte) 482 { 483 struct viapcib_softc *sc; 484 485 sc = (struct viapcib_softc *)opaque; 486 487 DPRINTF(("viapcib_smbus_write_byte(%p, 0x%x, 0x%x, 0x%x)\n", opaque, 488 slave, cmd, byte)); 489 490 viapcib_clear(sc); 491 if (viapcib_busy(sc)) 492 return EBUSY; 493 494 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 495 viapcib_smbus_write(sc, SMBHSTCMD, cmd); 496 viapcib_smbus_write(sc, SMBHSTDAT0, byte); 497 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE); 498 if (viapcib_wait(sc)) 499 return EBUSY; 500 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE); 501 502 return viapcib_wait(sc); 503 } 504 505 static int 506 viapcib_smbus_read_byte(void *opaque, i2c_addr_t slave, uint8_t cmd, 507 int8_t *pbyte) 508 { 509 struct viapcib_softc *sc; 510 int rv; 511 512 sc = (struct viapcib_softc *)opaque; 513 514 DPRINTF(("viapcib_smbus_read_byte(%p, 0x%x, 0x%x, %p)\n", opaque, 515 slave, cmd, pbyte)); 516 517 viapcib_clear(sc); 518 if (viapcib_busy(sc)) 519 return EBUSY; 520 521 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 522 viapcib_smbus_write(sc, SMBHSTCMD, cmd); 523 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE); 524 if (viapcib_wait(sc)) 525 return EBUSY; 526 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE); 527 rv = viapcib_wait(sc); 528 if (rv == 0) 529 *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0); 530 531 return rv; 532 } 533 534 static int 535 viapcib_smbus_write_word(void *opaque, i2c_addr_t slave, uint8_t cmd, 536 int16_t word) 537 { 538 struct viapcib_softc *sc; 539 540 sc = (struct viapcib_softc *)opaque; 541 542 DPRINTF(("viapcib_smbus_write_word(%p, 0x%x, 0x%x, 0x%x)\n", opaque, 543 slave, cmd, word)); 544 545 viapcib_clear(sc); 546 if (viapcib_busy(sc)) 547 return EBUSY; 548 549 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 550 viapcib_smbus_write(sc, SMBHSTCMD, cmd); 551 viapcib_smbus_write(sc, SMBHSTDAT0, word & 0x00ff); 552 viapcib_smbus_write(sc, SMBHSTDAT1, (word & 0xff00) >> 8); 553 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD); 554 if (viapcib_wait(sc)) 555 return EBUSY; 556 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD); 557 558 return viapcib_wait(sc); 559 } 560 561 static int 562 viapcib_smbus_read_word(void *opaque, i2c_addr_t slave, uint8_t cmd, 563 int16_t *pword) 564 { 565 struct viapcib_softc *sc; 566 int rv; 567 int8_t high, low; 568 569 sc = (struct viapcib_softc *)opaque; 570 571 DPRINTF(("viapcib_smbus_read_word(%p, 0x%x, 0x%x, %p)\n", opaque, 572 slave, cmd, pword)); 573 574 viapcib_clear(sc); 575 if (viapcib_busy(sc)) 576 return EBUSY; 577 578 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 579 viapcib_smbus_write(sc, SMBHSTCMD, cmd); 580 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD); 581 if (viapcib_wait(sc)) 582 return EBUSY; 583 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD); 584 585 rv = viapcib_wait(sc); 586 if (rv == 0) { 587 low = viapcib_smbus_read(sc, SMBHSTDAT0); 588 high = viapcib_smbus_read(sc, SMBHSTDAT1); 589 *pword = ((high & 0xff) << 8) | (low & 0xff); 590 } 591 592 return rv; 593 } 594 595 static int 596 viapcib_smbus_block_write(void *opaque, i2c_addr_t slave, uint8_t cmd, 597 int cnt, void *data) 598 { 599 struct viapcib_softc *sc; 600 int8_t *buf; 601 int remain, len, i; 602 int rv; 603 604 sc = (struct viapcib_softc *)opaque; 605 buf = (int8_t *)data; 606 rv = 0; 607 608 DPRINTF(("viapcib_smbus_block_write(%p, 0x%x, 0x%x, %d, %p)\n", 609 opaque, slave, cmd, cnt, data)); 610 611 viapcib_clear(sc); 612 if (viapcib_busy(sc)) 613 return EBUSY; 614 615 remain = cnt; 616 while (remain) { 617 len = min(remain, SMB_MAXBLOCKSIZE); 618 619 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1); 620 viapcib_smbus_write(sc, SMBHSTCMD, cmd); 621 viapcib_smbus_write(sc, SMBHSTDAT0, len); 622 i = viapcib_smbus_read(sc, SMBHSTCNT); 623 /* XXX FreeBSD does this, but it looks wrong */ 624 for (i = 0; i < len; i++) { 625 viapcib_smbus_write(sc, SMBBLKDAT, 626 buf[cnt - remain + i]); 627 } 628 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK); 629 if (viapcib_wait(sc)) 630 return EBUSY; 631 viapcib_smbus_write(sc, SMBHSTCNT, 632 SMBHSTCNT_START | SMBHSTCNT_BLOCK); 633 if (viapcib_wait(sc)) 634 return EBUSY; 635 636 remain -= len; 637 } 638 639 return rv; 640 } 641 642 static int 643 viapcib_smbus_block_read(void *opaque, i2c_addr_t slave, uint8_t cmd, 644 int cnt, void *data) 645 { 646 struct viapcib_softc *sc; 647 int8_t *buf; 648 int remain, len, i; 649 int rv; 650 651 sc = (struct viapcib_softc *)opaque; 652 buf = (int8_t *)data; 653 rv = 0; 654 655 DPRINTF(("viapcib_smbus_block_read(%p, 0x%x, 0x%x, %d, %p)\n", 656 opaque, slave, cmd, cnt, data)); 657 658 viapcib_clear(sc); 659 if (viapcib_busy(sc)) 660 return EBUSY; 661 662 remain = cnt; 663 while (remain) { 664 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1); 665 viapcib_smbus_write(sc, SMBHSTCMD, cmd); 666 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK); 667 if (viapcib_wait(sc)) 668 return EBUSY; 669 viapcib_smbus_write(sc, SMBHSTCNT, 670 SMBHSTCNT_START | SMBHSTCNT_BLOCK); 671 if (viapcib_wait(sc)) 672 return EBUSY; 673 674 len = viapcib_smbus_read(sc, SMBHSTDAT0); 675 i = viapcib_smbus_read(sc, SMBHSTCNT); 676 677 len = min(len, remain); 678 679 /* FreeBSD does this too... */ 680 for (i = 0; i < len; i++) { 681 buf[cnt - remain + i] = 682 viapcib_smbus_read(sc, SMBBLKDAT); 683 } 684 685 remain -= len; 686 } 687 688 return rv; 689 } 690