amdpm.c revision 119796
1/*- 2 * Copyright (c) 2000 Matthew C. Forman 3 * 4 * Based (heavily) on alpm.c which is: 5 * 6 * Copyright (c) 1998, 1999 Nicolas Souchu 7 * All rights reserved. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 */ 30 31/* 32 * Power management function/SMBus function support for the AMD 756 chip. 33 */ 34 35#include <sys/cdefs.h> 36__FBSDID("$FreeBSD: head/sys/pci/amdpm.c 119796 2003-09-06 13:56:56Z dfr $"); 37 38#include <sys/param.h> 39#include <sys/kernel.h> 40#include <sys/systm.h> 41#include <sys/module.h> 42#include <sys/bus.h> 43#include <sys/uio.h> 44 45#include <machine/bus_pio.h> 46#include <machine/bus_memio.h> 47#include <machine/bus.h> 48#include <machine/clock.h> 49#include <machine/resource.h> 50#include <sys/rman.h> 51 52#include <dev/pci/pcivar.h> 53#include <dev/pci/pcireg.h> 54 55#include <dev/iicbus/iiconf.h> 56#include <dev/smbus/smbconf.h> 57#include "smbus_if.h" 58 59#define AMDPM_DEBUG(x) if (amdpm_debug) (x) 60 61#ifdef DEBUG 62static int amdpm_debug = 1; 63#else 64static int amdpm_debug = 0; 65#endif 66 67#define AMDPM_VENDORID_AMD 0x1022 68#define AMDPM_DEVICEID_AMD756PM 0x740b 69#define AMDPM_DEVICEID_AMD766PM 0x7413 70#define AMDPM_DEVICEID_AMD768PM 0x7443 71 72/* nVidia nForce chipset */ 73#define AMDPM_VENDORID_NVIDIA 0x10de 74#define AMDPM_DEVICEID_NF_SMB 0x01b4 75 76/* PCI Configuration space registers */ 77#define AMDPCI_PMBASE 0x58 78#define NFPCI_PMBASE 0x14 79 80#define AMDPCI_GEN_CONFIG_PM 0x41 81#define AMDPCI_PMIOEN (1<<7) 82 83#define AMDPCI_SCIINT_CONFIG_PM 0x42 84#define AMDPCI_SCISEL_IRQ11 11 85 86#define AMDPCI_REVID 0x08 87 88/* 89 * I/O registers. 90 * Base address programmed via AMDPCI_PMBASE. 91 */ 92 93#define AMDSMB_GLOBAL_STATUS (0x00) 94#define AMDSMB_GS_TO_STS (1<<5) 95#define AMDSMB_GS_HCYC_STS (1<<4) 96#define AMDSMB_GS_HST_STS (1<<3) 97#define AMDSMB_GS_PRERR_STS (1<<2) 98#define AMDSMB_GS_COL_STS (1<<1) 99#define AMDSMB_GS_ABRT_STS (1<<0) 100#define AMDSMB_GS_CLEAR_STS (AMDSMB_GS_TO_STS|AMDSMB_GS_HCYC_STS|AMDSMB_GS_PRERR_STS|AMDSMB_GS_COL_STS|AMDSMB_GS_ABRT_STS) 101 102#define AMDSMB_GLOBAL_ENABLE (0x02) 103#define AMDSMB_GE_ABORT (1<<5) 104#define AMDSMB_GE_HCYC_EN (1<<4) 105#define AMDSMB_GE_HOST_STC (1<<3) 106#define AMDSMB_GE_CYC_QUICK 0 107#define AMDSMB_GE_CYC_BYTE 1 108#define AMDSMB_GE_CYC_BDATA 2 109#define AMDSMB_GE_CYC_WDATA 3 110#define AMDSMB_GE_CYC_PROCCALL 4 111#define AMDSMB_GE_CYC_BLOCK 5 112 113#define AMDSMB_HSTADDR (0x04) 114#define AMDSMB_HSTDATA (0x06) 115#define AMDSMB_HSTCMD (0x08) 116#define AMDSMB_HSTDFIFO (0x09) 117#define AMDSMB_HSLVDATA (0x0A) 118#define AMDSMB_HSLVDA (0x0C) 119#define AMDSMB_HSLVDDR (0x0E) 120#define AMDSMB_SNPADDR (0x0F) 121 122struct amdpm_softc { 123 int base; 124 int rid; 125 struct resource *res; 126 bus_space_tag_t smbst; 127 bus_space_handle_t smbsh; 128 129 device_t smbus; 130}; 131 132#define AMDPM_SMBINB(amdpm,register) \ 133 (bus_space_read_1(amdpm->smbst, amdpm->smbsh, register)) 134#define AMDPM_SMBOUTB(amdpm,register,value) \ 135 (bus_space_write_1(amdpm->smbst, amdpm->smbsh, register, value)) 136#define AMDPM_SMBINW(amdpm,register) \ 137 (bus_space_read_2(amdpm->smbst, amdpm->smbsh, register)) 138#define AMDPM_SMBOUTW(amdpm,register,value) \ 139 (bus_space_write_2(amdpm->smbst, amdpm->smbsh, register, value)) 140 141static int 142amdpm_probe(device_t dev) 143{ 144 u_long base; 145 u_int16_t vid; 146 u_int16_t did; 147 148 vid = pci_get_vendor(dev); 149 did = pci_get_device(dev); 150 if ((vid == AMDPM_VENDORID_AMD) && 151 ((did == AMDPM_DEVICEID_AMD756PM) || 152 (did == AMDPM_DEVICEID_AMD766PM) || 153 (did == AMDPM_DEVICEID_AMD768PM))) { 154 device_set_desc(dev, "AMD 756/766/768 Power Management Controller"); 155 156 /* 157 * We have to do this, since the BIOS won't give us the 158 * resource info (not mine, anyway). 159 */ 160 base = pci_read_config(dev, AMDPCI_PMBASE, 4); 161 base &= 0xff00; 162 bus_set_resource(dev, SYS_RES_IOPORT, AMDPCI_PMBASE, 163 base+0xe0, 32); 164 return (0); 165 } 166 167 if ((vid == AMDPM_VENDORID_NVIDIA) && 168 (did == AMDPM_DEVICEID_NF_SMB)) { 169 device_set_desc(dev, "nForce SMBus Controller"); 170 171 /* 172 * We have to do this, since the BIOS won't give us the 173 * resource info (not mine, anyway). 174 */ 175 base = pci_read_config(dev, NFPCI_PMBASE, 4); 176 base &= 0xff00; 177 bus_set_resource(dev, SYS_RES_IOPORT, NFPCI_PMBASE, 178 base, 32); 179 180 return (0); 181 } 182 183 return ENXIO; 184} 185 186static int 187amdpm_attach(device_t dev) 188{ 189 struct amdpm_softc *amdpm_sc = device_get_softc(dev); 190 u_char val_b; 191 192 /* Enable I/O block access */ 193 val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1); 194 pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1); 195 196 /* Allocate I/O space */ 197 if (pci_get_vendor(dev) == AMDPM_VENDORID_AMD) 198 amdpm_sc->rid = AMDPCI_PMBASE; 199 else 200 amdpm_sc->rid = NFPCI_PMBASE; 201 amdpm_sc->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &amdpm_sc->rid, 0, ~0, 1, RF_ACTIVE); 202 203 if (amdpm_sc->res == NULL) { 204 device_printf(dev, "could not map i/o space\n"); 205 return (ENXIO); 206 } 207 208 amdpm_sc->smbst = rman_get_bustag(amdpm_sc->res); 209 amdpm_sc->smbsh = rman_get_bushandle(amdpm_sc->res); 210 211 /* Allocate a new smbus device */ 212 amdpm_sc->smbus = device_add_child(dev, "smbus", -1); 213 if (!amdpm_sc->smbus) 214 return (EINVAL); 215 216 bus_generic_attach(dev); 217 218 return (0); 219} 220 221static int 222amdpm_detach(device_t dev) 223{ 224 struct amdpm_softc *amdpm_sc = device_get_softc(dev); 225 226 if (amdpm_sc->smbus) { 227 device_delete_child(dev, amdpm_sc->smbus); 228 amdpm_sc->smbus = NULL; 229 } 230 231 if (amdpm_sc->res) 232 bus_release_resource(dev, SYS_RES_IOPORT, amdpm_sc->rid, 233 amdpm_sc->res); 234 235 return (0); 236} 237 238static int 239amdpm_callback(device_t dev, int index, caddr_t *data) 240{ 241 int error = 0; 242 243 switch (index) { 244 case SMB_REQUEST_BUS: 245 case SMB_RELEASE_BUS: 246 break; 247 default: 248 error = EINVAL; 249 } 250 251 return (error); 252} 253 254static int 255amdpm_clear(struct amdpm_softc *sc) 256{ 257 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS); 258 DELAY(10); 259 260 return (0); 261} 262 263#if 0 264static int 265amdpm_abort(struct amdpm_softc *sc) 266{ 267 u_short l; 268 269 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 270 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT); 271 272 return (0); 273} 274#endif 275 276static int 277amdpm_idle(struct amdpm_softc *sc) 278{ 279 u_short sts; 280 281 sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS); 282 283 AMDPM_DEBUG(printf("amdpm: busy? STS=0x%x\n", sts)); 284 285 return (~(sts & AMDSMB_GS_HST_STS)); 286} 287 288/* 289 * Poll the SMBus controller 290 */ 291static int 292amdpm_wait(struct amdpm_softc *sc) 293{ 294 int count = 10000; 295 u_short sts = 0; 296 int error; 297 298 /* Wait for command to complete (SMBus controller is idle) */ 299 while(count--) { 300 DELAY(10); 301 sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS); 302 if (!(sts & AMDSMB_GS_HST_STS)) 303 break; 304 } 305 306 AMDPM_DEBUG(printf("amdpm: STS=0x%x (count=%d)\n", sts, count)); 307 308 error = SMB_ENOERR; 309 310 if (!count) 311 error |= SMB_ETIMEOUT; 312 313 if (sts & AMDSMB_GS_ABRT_STS) 314 error |= SMB_EABORT; 315 316 if (sts & AMDSMB_GS_COL_STS) 317 error |= SMB_ENOACK; 318 319 if (sts & AMDSMB_GS_PRERR_STS) 320 error |= SMB_EBUSERR; 321 322 if (error != SMB_ENOERR) 323 amdpm_clear(sc); 324 325 return (error); 326} 327 328static int 329amdpm_quick(device_t dev, u_char slave, int how) 330{ 331 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 332 int error; 333 u_short l; 334 335 amdpm_clear(sc); 336 if (!amdpm_idle(sc)) 337 return (EBUSY); 338 339 switch (how) { 340 case SMB_QWRITE: 341 AMDPM_DEBUG(printf("amdpm: QWRITE to 0x%x", slave)); 342 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 343 break; 344 case SMB_QREAD: 345 AMDPM_DEBUG(printf("amdpm: QREAD to 0x%x", slave)); 346 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 347 break; 348 default: 349 panic("%s: unknown QUICK command (%x)!", __func__, how); 350 } 351 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 352 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC); 353 354 error = amdpm_wait(sc); 355 356 AMDPM_DEBUG(printf(", error=0x%x\n", error)); 357 358 return (error); 359} 360 361static int 362amdpm_sendb(device_t dev, u_char slave, char byte) 363{ 364 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 365 int error; 366 u_short l; 367 368 amdpm_clear(sc); 369 if (!amdpm_idle(sc)) 370 return (SMB_EBUSY); 371 372 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 373 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte); 374 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 375 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC); 376 377 error = amdpm_wait(sc); 378 379 AMDPM_DEBUG(printf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); 380 381 return (error); 382} 383 384static int 385amdpm_recvb(device_t dev, u_char slave, char *byte) 386{ 387 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 388 int error; 389 u_short l; 390 391 amdpm_clear(sc); 392 if (!amdpm_idle(sc)) 393 return (SMB_EBUSY); 394 395 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 396 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 397 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC); 398 399 if ((error = amdpm_wait(sc)) == SMB_ENOERR) 400 *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 401 402 AMDPM_DEBUG(printf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); 403 404 return (error); 405} 406 407static int 408amdpm_writeb(device_t dev, u_char slave, char cmd, char byte) 409{ 410 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 411 int error; 412 u_short l; 413 414 amdpm_clear(sc); 415 if (!amdpm_idle(sc)) 416 return (SMB_EBUSY); 417 418 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 419 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte); 420 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 421 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 422 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC); 423 424 error = amdpm_wait(sc); 425 426 AMDPM_DEBUG(printf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); 427 428 return (error); 429} 430 431static int 432amdpm_readb(device_t dev, u_char slave, char cmd, char *byte) 433{ 434 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 435 int error; 436 u_short l; 437 438 amdpm_clear(sc); 439 if (!amdpm_idle(sc)) 440 return (SMB_EBUSY); 441 442 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 443 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 444 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 445 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC); 446 447 if ((error = amdpm_wait(sc)) == SMB_ENOERR) 448 *byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 449 450 AMDPM_DEBUG(printf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); 451 452 return (error); 453} 454 455static int 456amdpm_writew(device_t dev, u_char slave, char cmd, short word) 457{ 458 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 459 int error; 460 u_short l; 461 462 amdpm_clear(sc); 463 if (!amdpm_idle(sc)) 464 return (SMB_EBUSY); 465 466 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 467 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word); 468 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 469 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 470 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC); 471 472 error = amdpm_wait(sc); 473 474 AMDPM_DEBUG(printf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); 475 476 return (error); 477} 478 479static int 480amdpm_readw(device_t dev, u_char slave, char cmd, short *word) 481{ 482 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 483 int error; 484 u_short l; 485 486 amdpm_clear(sc); 487 if (!amdpm_idle(sc)) 488 return (SMB_EBUSY); 489 490 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 491 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 492 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 493 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC); 494 495 if ((error = amdpm_wait(sc)) == SMB_ENOERR) 496 *word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 497 498 AMDPM_DEBUG(printf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); 499 500 return (error); 501} 502 503static int 504amdpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 505{ 506 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 507 u_char remain, len, i; 508 int error = SMB_ENOERR; 509 u_short l; 510 511 amdpm_clear(sc); 512 if(!amdpm_idle(sc)) 513 return (SMB_EBUSY); 514 515 remain = count; 516 while (remain) { 517 len = min(remain, 32); 518 519 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB); 520 521 /* 522 * Do we have to reset the internal 32-byte buffer? 523 * Can't see how to do this from the data sheet. 524 */ 525 526 AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, len); 527 528 /* Fill the 32-byte internal buffer */ 529 for (i=0; i<len; i++) { 530 AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[count-remain+i]); 531 DELAY(2); 532 } 533 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 534 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 535 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC); 536 537 if ((error = amdpm_wait(sc)) != SMB_ENOERR) 538 goto error; 539 540 remain -= len; 541 } 542 543error: 544 AMDPM_DEBUG(printf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 545 546 return (error); 547} 548 549static int 550amdpm_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 551{ 552 struct amdpm_softc *sc = (struct amdpm_softc *)device_get_softc(dev); 553 u_char remain, len, i; 554 int error = SMB_ENOERR; 555 u_short l; 556 557 amdpm_clear(sc); 558 if (!amdpm_idle(sc)) 559 return (SMB_EBUSY); 560 561 remain = count; 562 while (remain) { 563 AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB); 564 565 AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd); 566 567 l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE); 568 AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC); 569 570 if ((error = amdpm_wait(sc)) != SMB_ENOERR) 571 goto error; 572 573 len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA); 574 575 /* Read the 32-byte internal buffer */ 576 for (i=0; i<len; i++) { 577 buf[count-remain+i] = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO); 578 DELAY(2); 579 } 580 581 remain -= len; 582 } 583error: 584 AMDPM_DEBUG(printf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); 585 586 return (error); 587} 588 589static devclass_t amdpm_devclass; 590 591static device_method_t amdpm_methods[] = { 592 /* Device interface */ 593 DEVMETHOD(device_probe, amdpm_probe), 594 DEVMETHOD(device_attach, amdpm_attach), 595 DEVMETHOD(device_detach, amdpm_detach), 596 597 /* SMBus interface */ 598 DEVMETHOD(smbus_callback, amdpm_callback), 599 DEVMETHOD(smbus_quick, amdpm_quick), 600 DEVMETHOD(smbus_sendb, amdpm_sendb), 601 DEVMETHOD(smbus_recvb, amdpm_recvb), 602 DEVMETHOD(smbus_writeb, amdpm_writeb), 603 DEVMETHOD(smbus_readb, amdpm_readb), 604 DEVMETHOD(smbus_writew, amdpm_writew), 605 DEVMETHOD(smbus_readw, amdpm_readw), 606 DEVMETHOD(smbus_bwrite, amdpm_bwrite), 607 DEVMETHOD(smbus_bread, amdpm_bread), 608 609 { 0, 0 } 610}; 611 612static driver_t amdpm_driver = { 613 "amdpm", 614 amdpm_methods, 615 sizeof(struct amdpm_softc), 616}; 617 618DRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0); 619 620MODULE_DEPEND(amdpm, pci, 1, 1, 1); 621MODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 622MODULE_VERSION(amdpm, 1); 623 624