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