xref: /freebsd/sys/dev/alpm/alpm.c (revision 38a52bd3)
1 /*-
2  * Copyright (c) 1998, 1999, 2001 Nicolas Souchu
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /*
28  * Power Management support for the Acer M15x3 chipsets
29  */
30 
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD$");
33 
34 #include <sys/param.h>
35 #include <sys/bus.h>
36 #include <sys/kernel.h>
37 #include <sys/lock.h>
38 #include <sys/module.h>
39 #include <sys/mutex.h>
40 #include <sys/systm.h>
41 
42 #include <machine/bus.h>
43 #include <machine/resource.h>
44 #include <sys/rman.h>
45 
46 #include <dev/pci/pcivar.h>
47 #include <dev/pci/pcireg.h>
48 
49 #include <dev/smbus/smbconf.h>
50 #include "smbus_if.h"
51 
52 #define ALPM_DEBUG(x)	if (alpm_debug) (x)
53 
54 #ifdef DEBUG
55 static int alpm_debug = 1;
56 #else
57 static int alpm_debug = 0;
58 #endif
59 
60 #define ACER_M1543_PMU_ID	0x710110b9
61 
62 /*
63  * I/O registers offsets - the base address is programmed via the
64  * SMBBA PCI configuration register
65  */
66 #define SMBSTS		0x0	/* SMBus host/slave status register */
67 #define SMBCMD		0x1	/* SMBus host/slave command register */
68 #define SMBSTART	0x2	/* start to generate programmed cycle */
69 #define SMBHADDR	0x3	/* host address register */
70 #define SMBHDATA	0x4	/* data A register for host controller */
71 #define SMBHDATB	0x5	/* data B register for host controller */
72 #define SMBHBLOCK	0x6	/* block register for host controller */
73 #define SMBHCMD		0x7	/* command register for host controller */
74 
75 /* SMBHADDR mask. */
76 #define	LSB		0x1	/* XXX: Better name: Read/Write? */
77 
78 /* SMBSTS masks */
79 #define TERMINATE	0x80
80 #define BUS_COLLI	0x40
81 #define DEVICE_ERR	0x20
82 #define SMI_I_STS	0x10
83 #define HST_BSY		0x08
84 #define IDL_STS		0x04
85 #define HSTSLV_STS	0x02
86 #define HSTSLV_BSY	0x01
87 
88 /* SMBCMD masks */
89 #define SMB_BLK_CLR	0x80
90 #define T_OUT_CMD	0x08
91 #define ABORT_HOST	0x04
92 
93 /* SMBus commands */
94 #define SMBQUICK	0x00
95 #define SMBSRBYTE	0x10		/* send/receive byte */
96 #define SMBWRBYTE	0x20		/* write/read byte */
97 #define SMBWRWORD	0x30		/* write/read word */
98 #define SMBWRBLOCK	0x40		/* write/read block */
99 
100 /* PCI configuration registers and masks
101  */
102 #define COM		0x4
103 #define COM_ENABLE_IO	0x1
104 
105 #define SMBBA		PCIR_BAR(1)
106 
107 #define ATPC		0x5b
108 #define ATPC_SMBCTRL	0x04 		/* XX linux has this as 0x6 */
109 
110 #define SMBHSI		0xe0
111 #define SMBHSI_SLAVE	0x2
112 #define SMBHSI_HOST	0x1
113 
114 #define SMBHCBC		0xe2
115 #define SMBHCBC_CLOCK	0x70
116 
117 #define SMBCLOCK_149K	0x0
118 #define SMBCLOCK_74K	0x20
119 #define SMBCLOCK_37K	0x40
120 #define SMBCLOCK_223K	0x80
121 #define SMBCLOCK_111K	0xa0
122 #define SMBCLOCK_55K	0xc0
123 
124 struct alpm_softc {
125 	int base;
126 	struct resource *res;
127         bus_space_tag_t smbst;
128         bus_space_handle_t smbsh;
129 	device_t smbus;
130 	struct mtx lock;
131 };
132 
133 #define	ALPM_LOCK(alpm)		mtx_lock(&(alpm)->lock)
134 #define	ALPM_UNLOCK(alpm)	mtx_unlock(&(alpm)->lock)
135 #define	ALPM_LOCK_ASSERT(alpm)	mtx_assert(&(alpm)->lock, MA_OWNED)
136 
137 #define ALPM_SMBINB(alpm,register) \
138 	(bus_space_read_1(alpm->smbst, alpm->smbsh, register))
139 #define ALPM_SMBOUTB(alpm,register,value) \
140 	(bus_space_write_1(alpm->smbst, alpm->smbsh, register, value))
141 
142 static int	alpm_detach(device_t dev);
143 
144 static int
145 alpm_probe(device_t dev)
146 {
147 
148 	if (pci_get_devid(dev) == ACER_M1543_PMU_ID) {
149 		device_set_desc(dev, "AcerLabs M15x3 Power Management Unit");
150 
151 		return (BUS_PROBE_DEFAULT);
152 	}
153 
154 	return (ENXIO);
155 }
156 
157 static int
158 alpm_attach(device_t dev)
159 {
160 	int rid;
161 	u_int32_t l;
162 	struct alpm_softc *alpm;
163 
164 	alpm = device_get_softc(dev);
165 
166 	/* Unlock SMBIO base register access */
167 	l = pci_read_config(dev, ATPC, 1);
168 	pci_write_config(dev, ATPC, l & ~ATPC_SMBCTRL, 1);
169 
170 	/*
171 	 * XX linux sets clock to 74k, should we?
172 	l = pci_read_config(dev, SMBHCBC, 1);
173 	l &= 0x1f;
174 	l |= SMBCLOCK_74K;
175 	pci_write_config(dev, SMBHCBC, l, 1);
176 	 */
177 
178 	if (bootverbose || alpm_debug) {
179 		l = pci_read_config(dev, SMBHSI, 1);
180 		device_printf(dev, "%s/%s",
181 			(l & SMBHSI_HOST) ? "host":"nohost",
182 			(l & SMBHSI_SLAVE) ? "slave":"noslave");
183 
184 		l = pci_read_config(dev, SMBHCBC, 1);
185 		switch (l & SMBHCBC_CLOCK) {
186 		case SMBCLOCK_149K:
187 			printf(" 149K");
188 			break;
189 		case SMBCLOCK_74K:
190 			printf(" 74K");
191 			break;
192 		case SMBCLOCK_37K:
193 			printf(" 37K");
194 			break;
195 		case SMBCLOCK_223K:
196 			printf(" 223K");
197 			break;
198 		case SMBCLOCK_111K:
199 			printf(" 111K");
200 			break;
201 		case SMBCLOCK_55K:
202 			printf(" 55K");
203 			break;
204 		default:
205 			printf("unknown");
206 			break;
207 		}
208 		printf("\n");
209 	}
210 
211 	rid = SMBBA;
212 	alpm->res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
213 	    RF_ACTIVE);
214 
215 	if (alpm->res == NULL) {
216 		device_printf(dev,"Could not allocate Bus space\n");
217 		return (ENXIO);
218 	}
219 	alpm->smbst = rman_get_bustag(alpm->res);
220 	alpm->smbsh = rman_get_bushandle(alpm->res);
221 	mtx_init(&alpm->lock, device_get_nameunit(dev), "alpm", MTX_DEF);
222 
223 	/* attach the smbus */
224 	alpm->smbus = device_add_child(dev, "smbus", -1);
225 	if (alpm->smbus == NULL) {
226 		alpm_detach(dev);
227 		return (EINVAL);
228 	}
229 	bus_generic_attach(dev);
230 
231 	return (0);
232 }
233 
234 static int
235 alpm_detach(device_t dev)
236 {
237 	struct alpm_softc *alpm = device_get_softc(dev);
238 
239 	if (alpm->smbus) {
240 		device_delete_child(dev, alpm->smbus);
241 		alpm->smbus = NULL;
242 	}
243 	mtx_destroy(&alpm->lock);
244 
245 	if (alpm->res)
246 		bus_release_resource(dev, SYS_RES_IOPORT, SMBBA, alpm->res);
247 
248 	return (0);
249 }
250 
251 static int
252 alpm_callback(device_t dev, int index, void *data)
253 {
254 	int error = 0;
255 
256 	switch (index) {
257 	case SMB_REQUEST_BUS:
258 	case SMB_RELEASE_BUS:
259 		/* ok, bus allocation accepted */
260 		break;
261 	default:
262 		error = EINVAL;
263 	}
264 
265 	return (error);
266 }
267 
268 static int
269 alpm_clear(struct alpm_softc *sc)
270 {
271 	ALPM_SMBOUTB(sc, SMBSTS, 0xff);
272 	DELAY(10);
273 
274 	return (0);
275 }
276 
277 #if 0
278 static int
279 alpm_abort(struct alpm_softc *sc)
280 {
281 	ALPM_SMBOUTB(sc, SMBCMD, T_OUT_CMD | ABORT_HOST);
282 
283 	return (0);
284 }
285 #endif
286 
287 static int
288 alpm_idle(struct alpm_softc *sc)
289 {
290 	u_char sts;
291 
292 	sts = ALPM_SMBINB(sc, SMBSTS);
293 
294 	ALPM_DEBUG(printf("alpm: idle? STS=0x%x\n", sts));
295 
296 	return (sts & IDL_STS);
297 }
298 
299 /*
300  * Poll the SMBus controller
301  */
302 static int
303 alpm_wait(struct alpm_softc *sc)
304 {
305 	int count = 10000;
306 	u_char sts = 0;
307 	int error;
308 
309 	/* wait for command to complete and SMBus controller is idle */
310 	while (count--) {
311 		DELAY(10);
312 		sts = ALPM_SMBINB(sc, SMBSTS);
313 		if (sts & SMI_I_STS)
314 			break;
315 	}
316 
317 	ALPM_DEBUG(printf("alpm: STS=0x%x\n", sts));
318 
319 	error = SMB_ENOERR;
320 
321 	if (!count)
322 		error |= SMB_ETIMEOUT;
323 
324 	if (sts & TERMINATE)
325 		error |= SMB_EABORT;
326 
327 	if (sts & BUS_COLLI)
328 		error |= SMB_ENOACK;
329 
330 	if (sts & DEVICE_ERR)
331 		error |= SMB_EBUSERR;
332 
333 	if (error != SMB_ENOERR)
334 		alpm_clear(sc);
335 
336 	return (error);
337 }
338 
339 static int
340 alpm_quick(device_t dev, u_char slave, int how)
341 {
342 	struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
343 	int error;
344 
345 	ALPM_LOCK(sc);
346 	alpm_clear(sc);
347 	if (!alpm_idle(sc)) {
348 		ALPM_UNLOCK(sc);
349 		return (EBUSY);
350 	}
351 
352 	switch (how) {
353 	case SMB_QWRITE:
354 		ALPM_DEBUG(printf("alpm: QWRITE to 0x%x", slave));
355 		ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
356 		break;
357 	case SMB_QREAD:
358 		ALPM_DEBUG(printf("alpm: QREAD to 0x%x", slave));
359 		ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
360 		break;
361 	default:
362 		panic("%s: unknown QUICK command (%x)!", __func__,
363 			how);
364 	}
365 	ALPM_SMBOUTB(sc, SMBCMD, SMBQUICK);
366 	ALPM_SMBOUTB(sc, SMBSTART, 0xff);
367 
368 	error = alpm_wait(sc);
369 
370 	ALPM_DEBUG(printf(", error=0x%x\n", error));
371 	ALPM_UNLOCK(sc);
372 
373 	return (error);
374 }
375 
376 static int
377 alpm_sendb(device_t dev, u_char slave, char byte)
378 {
379 	struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
380 	int error;
381 
382 	ALPM_LOCK(sc);
383 	alpm_clear(sc);
384 	if (!alpm_idle(sc)) {
385 		ALPM_UNLOCK(sc);
386 		return (SMB_EBUSY);
387 	}
388 
389 	ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
390 	ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE);
391 	ALPM_SMBOUTB(sc, SMBHDATA, byte);
392 	ALPM_SMBOUTB(sc, SMBSTART, 0xff);
393 
394 	error = alpm_wait(sc);
395 
396 	ALPM_DEBUG(printf("alpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
397 	ALPM_UNLOCK(sc);
398 
399 	return (error);
400 }
401 
402 static int
403 alpm_recvb(device_t dev, u_char slave, char *byte)
404 {
405 	struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
406 	int error;
407 
408 	ALPM_LOCK(sc);
409 	alpm_clear(sc);
410 	if (!alpm_idle(sc)) {
411 		ALPM_UNLOCK(sc);
412 		return (SMB_EBUSY);
413 	}
414 
415 	ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
416 	ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE);
417 	ALPM_SMBOUTB(sc, SMBSTART, 0xff);
418 
419 	if ((error = alpm_wait(sc)) == SMB_ENOERR)
420 		*byte = ALPM_SMBINB(sc, SMBHDATA);
421 
422 	ALPM_DEBUG(printf("alpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
423 	ALPM_UNLOCK(sc);
424 
425 	return (error);
426 }
427 
428 static int
429 alpm_writeb(device_t dev, u_char slave, char cmd, char byte)
430 {
431 	struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
432 	int error;
433 
434 	ALPM_LOCK(sc);
435 	alpm_clear(sc);
436 	if (!alpm_idle(sc)) {
437 		ALPM_UNLOCK(sc);
438 		return (SMB_EBUSY);
439 	}
440 
441 	ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
442 	ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE);
443 	ALPM_SMBOUTB(sc, SMBHDATA, byte);
444 	ALPM_SMBOUTB(sc, SMBHCMD, cmd);
445 	ALPM_SMBOUTB(sc, SMBSTART, 0xff);
446 
447 	error = alpm_wait(sc);
448 
449 	ALPM_DEBUG(printf("alpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
450 	ALPM_UNLOCK(sc);
451 
452 	return (error);
453 }
454 
455 static int
456 alpm_readb(device_t dev, u_char slave, char cmd, char *byte)
457 {
458 	struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
459 	int error;
460 
461 	ALPM_LOCK(sc);
462 	alpm_clear(sc);
463 	if (!alpm_idle(sc)) {
464 		ALPM_UNLOCK(sc);
465 		return (SMB_EBUSY);
466 	}
467 
468 	ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
469 	ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE);
470 	ALPM_SMBOUTB(sc, SMBHCMD, cmd);
471 	ALPM_SMBOUTB(sc, SMBSTART, 0xff);
472 
473 	if ((error = alpm_wait(sc)) == SMB_ENOERR)
474 		*byte = ALPM_SMBINB(sc, SMBHDATA);
475 
476 	ALPM_DEBUG(printf("alpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
477 	ALPM_UNLOCK(sc);
478 
479 	return (error);
480 }
481 
482 static int
483 alpm_writew(device_t dev, u_char slave, char cmd, short word)
484 {
485 	struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
486 	int error;
487 
488 	ALPM_LOCK(sc);
489 	alpm_clear(sc);
490 	if (!alpm_idle(sc)) {
491 		ALPM_UNLOCK(sc);
492 		return (SMB_EBUSY);
493 	}
494 
495 	ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
496 	ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD);
497 	ALPM_SMBOUTB(sc, SMBHDATA, word & 0x00ff);
498 	ALPM_SMBOUTB(sc, SMBHDATB, (word & 0xff00) >> 8);
499 	ALPM_SMBOUTB(sc, SMBHCMD, cmd);
500 	ALPM_SMBOUTB(sc, SMBSTART, 0xff);
501 
502 	error = alpm_wait(sc);
503 
504 	ALPM_DEBUG(printf("alpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
505 	ALPM_UNLOCK(sc);
506 
507 	return (error);
508 }
509 
510 static int
511 alpm_readw(device_t dev, u_char slave, char cmd, short *word)
512 {
513 	struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
514 	int error;
515 	u_char high, low;
516 
517 	ALPM_LOCK(sc);
518 	alpm_clear(sc);
519 	if (!alpm_idle(sc)) {
520 		ALPM_UNLOCK(sc);
521 		return (SMB_EBUSY);
522 	}
523 
524 	ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
525 	ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD);
526 	ALPM_SMBOUTB(sc, SMBHCMD, cmd);
527 	ALPM_SMBOUTB(sc, SMBSTART, 0xff);
528 
529 	if ((error = alpm_wait(sc)) == SMB_ENOERR) {
530 		low = ALPM_SMBINB(sc, SMBHDATA);
531 		high = ALPM_SMBINB(sc, SMBHDATB);
532 
533 		*word = ((high & 0xff) << 8) | (low & 0xff);
534 	}
535 
536 	ALPM_DEBUG(printf("alpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
537 	ALPM_UNLOCK(sc);
538 
539 	return (error);
540 }
541 
542 static int
543 alpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
544 {
545 	struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
546 	u_char i;
547 	int error;
548 
549 	if (count < 1 || count > 32)
550 		return (SMB_EINVAL);
551 
552 	ALPM_LOCK(sc);
553 	alpm_clear(sc);
554 	if(!alpm_idle(sc)) {
555 		ALPM_UNLOCK(sc);
556 		return (SMB_EBUSY);
557 	}
558 
559 	ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB);
560 
561 	/* set the cmd and reset the
562 	 * 32-byte long internal buffer */
563 	ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR);
564 
565 	ALPM_SMBOUTB(sc, SMBHDATA, count);
566 
567 	/* fill the 32-byte internal buffer */
568 	for (i = 0; i < count; i++) {
569 		ALPM_SMBOUTB(sc, SMBHBLOCK, buf[i]);
570 		DELAY(2);
571 	}
572 	ALPM_SMBOUTB(sc, SMBHCMD, cmd);
573 	ALPM_SMBOUTB(sc, SMBSTART, 0xff);
574 
575 	error = alpm_wait(sc);
576 
577 	ALPM_DEBUG(printf("alpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
578 	ALPM_UNLOCK(sc);
579 
580 	return (error);
581 }
582 
583 static int
584 alpm_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
585 {
586 	struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev);
587 	u_char data, len, i;
588 	int error;
589 
590 	if (*count < 1 || *count > 32)
591 		return (SMB_EINVAL);
592 
593 	ALPM_LOCK(sc);
594 	alpm_clear(sc);
595 	if (!alpm_idle(sc)) {
596 		ALPM_UNLOCK(sc);
597 		return (SMB_EBUSY);
598 	}
599 
600 	ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB);
601 
602 	/* set the cmd and reset the
603 	 * 32-byte long internal buffer */
604 	ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR);
605 
606 	ALPM_SMBOUTB(sc, SMBHCMD, cmd);
607 	ALPM_SMBOUTB(sc, SMBSTART, 0xff);
608 
609 	if ((error = alpm_wait(sc)) != SMB_ENOERR)
610 			goto error;
611 
612 	len = ALPM_SMBINB(sc, SMBHDATA);
613 
614 	/* read the 32-byte internal buffer */
615 	for (i = 0; i < len; i++) {
616 		data = ALPM_SMBINB(sc, SMBHBLOCK);
617 		if (i < *count)
618 			buf[i] = data;
619 		DELAY(2);
620 	}
621 	*count = len;
622 
623 error:
624 	ALPM_DEBUG(printf("alpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error));
625 	ALPM_UNLOCK(sc);
626 
627 	return (error);
628 }
629 
630 static device_method_t alpm_methods[] = {
631 	/* device interface */
632 	DEVMETHOD(device_probe,		alpm_probe),
633 	DEVMETHOD(device_attach,	alpm_attach),
634 	DEVMETHOD(device_detach,	alpm_detach),
635 
636 	/* smbus interface */
637 	DEVMETHOD(smbus_callback,	alpm_callback),
638 	DEVMETHOD(smbus_quick,		alpm_quick),
639 	DEVMETHOD(smbus_sendb,		alpm_sendb),
640 	DEVMETHOD(smbus_recvb,		alpm_recvb),
641 	DEVMETHOD(smbus_writeb,		alpm_writeb),
642 	DEVMETHOD(smbus_readb,		alpm_readb),
643 	DEVMETHOD(smbus_writew,		alpm_writew),
644 	DEVMETHOD(smbus_readw,		alpm_readw),
645 	DEVMETHOD(smbus_bwrite,		alpm_bwrite),
646 	DEVMETHOD(smbus_bread,		alpm_bread),
647 	{ 0, 0 }
648 };
649 
650 static driver_t alpm_driver = {
651 	"alpm",
652 	alpm_methods,
653 	sizeof(struct alpm_softc)
654 };
655 
656 DRIVER_MODULE(alpm, pci, alpm_driver, 0, 0);
657 DRIVER_MODULE(smbus, alpm, smbus_driver, 0, 0);
658 MODULE_DEPEND(alpm, pci, 1, 1, 1);
659 MODULE_DEPEND(alpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
660 MODULE_VERSION(alpm, 1);
661