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