amdpm.c revision 93040
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 * $FreeBSD: head/sys/pci/amdpm.c 93040 2002-03-23 18:27:16Z nsouch $
31 *
32 */
33
34/*
35 * Power management function/SMBus function support for the AMD 756 chip.
36 */
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 <pci/pcivar.h>
53#include <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
70/* PCI Configuration space registers */
71#define AMDPCI_PMBASE 0x58
72
73#define AMDPCI_GEN_CONFIG_PM 0x41
74#define AMDPCI_PMIOEN (1<<7)
75
76#define AMDPCI_SCIINT_CONFIG_PM 0x42
77#define AMDPCI_SCISEL_IRQ11 11
78
79#define AMDPCI_REVID 0x08
80
81/*
82 * I/O registers.
83 * Base address programmed via AMDPCI_PMBASE.
84 */
85#define AMDSMB_GLOBAL_STATUS 0xE0
86#define AMDSMB_GS_TO_STS (1<<5)
87#define AMDSMB_GS_HCYC_STS (1<<4)
88#define AMDSMB_GS_HST_STS (1<<3)
89#define AMDSMB_GS_PRERR_STS (1<<2)
90#define AMDSMB_GS_COL_STS (1<<1)
91#define AMDSMB_GS_ABRT_STS (1<<0)
92#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)
93
94#define AMDSMB_GLOBAL_ENABLE 0xE2
95#define AMDSMB_GE_ABORT (1<<5)
96#define AMDSMB_GE_HCYC_EN (1<<4)
97#define AMDSMB_GE_HOST_STC (1<<3)
98#define AMDSMB_GE_CYC_QUICK 0
99#define AMDSMB_GE_CYC_BYTE 1
100#define AMDSMB_GE_CYC_BDATA 2
101#define AMDSMB_GE_CYC_WDATA 3
102#define AMDSMB_GE_CYC_PROCCALL 4
103#define AMDSMB_GE_CYC_BLOCK 5
104
105#define AMDSMB_HSTADDR 0xE4
106#define AMDSMB_HSTDATA 0xE6
107#define AMDSMB_HSTCMD 0xE8
108#define AMDSMB_HSTDFIFO 0xE9
109#define AMDSMB_HSLVDATA 0xEA
110#define AMDSMB_HSLVDA 0xEC
111#define AMDSMB_HSLVDDR 0xEE
112#define AMDSMB_SNPADDR 0xEF
113
114struct amdpm_softc {
115	int base;
116	int rid;
117	struct resource *res;
118        bus_space_tag_t smbst;
119        bus_space_handle_t smbsh;
120};
121
122struct amdsmb_softc {
123	int base;
124	device_t smbus;
125	struct amdpm_softc *amdpm;
126};
127
128#define AMDPM_SMBINB(amdsmb,register) \
129	(bus_space_read_1(amdsmb->amdpm->smbst, amdsmb->amdpm->smbsh, register))
130#define AMDPM_SMBOUTB(amdsmb,register,value) \
131	(bus_space_write_1(amdsmb->amdpm->smbst, amdsmb->amdpm->smbsh, register, value))
132#define AMDPM_SMBINW(amdsmb,register) \
133	(bus_space_read_2(amdsmb->amdpm->smbst, amdsmb->amdpm->smbsh, register))
134#define AMDPM_SMBOUTW(amdsmb,register,value) \
135	(bus_space_write_2(amdsmb->amdpm->smbst, amdsmb->amdpm->smbsh, register, value))
136
137static int amdsmb_probe(device_t);
138static int amdsmb_attach(device_t);
139static int amdsmb_smb_callback(device_t, int, caddr_t *);
140static int amdsmb_smb_quick(device_t dev, u_char slave, int how);
141static int amdsmb_smb_sendb(device_t dev, u_char slave, char byte);
142static int amdsmb_smb_recvb(device_t dev, u_char slave, char *byte);
143static int amdsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte);
144static int amdsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte);
145static int amdsmb_smb_writew(device_t dev, u_char slave, char cmd, short word);
146static int amdsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word);
147static int amdsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
148static int amdsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *byte);
149
150static int amdpm_probe(device_t);
151static int amdpm_attach(device_t);
152
153
154static int
155amdpm_probe(device_t dev)
156{
157	u_long base;
158
159	if ((pci_get_vendor(dev) == AMDPM_VENDORID_AMD) &&
160	    (pci_get_device(dev) == AMDPM_DEVICEID_AMD756PM)) {
161	      device_set_desc(dev, "AMD 756 Power Management Controller");
162
163	      /*
164	       * We have to do this, since the BIOS won't give us the
165	       * resource info (not mine, anyway).
166	       */
167	      base = pci_read_config(dev, AMDPCI_PMBASE, 4);
168	      base &= 0xff00;
169	      bus_set_resource(dev, SYS_RES_IOPORT, AMDPCI_PMBASE, base, 256);
170	      return (0);
171	}
172	return ENXIO;
173}
174
175static int
176amdpm_attach(device_t dev)
177{
178	struct amdpm_softc *amdpm_sc = device_get_softc(dev);
179	u_char val_b;
180	int unit = device_get_unit(dev);
181	device_t smbinterface;
182
183	/* Enable I/O block access */
184	val_b = pci_read_config(dev, AMDPCI_GEN_CONFIG_PM, 1);
185	pci_write_config(dev, AMDPCI_GEN_CONFIG_PM, val_b | AMDPCI_PMIOEN, 1);
186
187	/* Allocate I/O space */
188	amdpm_sc->rid = AMDPCI_PMBASE;
189	amdpm_sc->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &amdpm_sc->rid, 0, ~0, 1, RF_ACTIVE);
190
191	if (amdpm_sc->res == NULL) {
192		device_printf(dev, "could not map i/o space\n");
193		return (ENXIO);
194	}
195
196	amdpm_sc->smbst = rman_get_bustag(amdpm_sc->res);
197	amdpm_sc->smbsh = rman_get_bushandle(amdpm_sc->res);
198
199	smbinterface = device_add_child(dev, "amdsmb", unit);
200	if (!smbinterface)
201		device_printf(dev, "could not add SMBus device\n");
202	else
203		device_probe_and_attach(smbinterface);
204
205	return (0);
206}
207
208static int
209amdsmb_probe(device_t dev)
210{
211	struct amdsmb_softc *amdsmb_sc = (struct amdsmb_softc *)device_get_softc(dev);
212
213	device_set_desc(dev, "AMD 756 SMBus interface");
214	device_printf(dev, "AMD 756 SMBus interface\n");
215
216	/* Allocate a new smbus device */
217	amdsmb_sc->smbus = device_add_child(dev, "smbus", -1);
218	if (!amdsmb_sc->smbus)
219		return (EINVAL);
220
221	bus_generic_attach(dev);
222
223	return (0);
224}
225
226static int
227amdsmb_attach(device_t dev)
228{
229	struct amdsmb_softc *amdsmb_sc = (struct amdsmb_softc *)device_get_softc(dev);
230
231	amdsmb_sc->amdpm = device_get_softc(device_get_parent(dev));
232
233	/* Probe and attach the smbus */
234	device_probe_and_attach(amdsmb_sc->smbus);
235
236	return (0);
237}
238
239static int
240amdsmb_smb_callback(device_t dev, int index, caddr_t *data)
241{
242	int error = 0;
243
244	switch (index) {
245	case SMB_REQUEST_BUS:
246	case SMB_RELEASE_BUS:
247		break;
248	default:
249		error = EINVAL;
250	}
251
252	return (error);
253}
254
255static int
256amdsmb_clear(struct amdsmb_softc *sc)
257{
258	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_STATUS, AMDSMB_GS_CLEAR_STS);
259	DELAY(10);
260
261	return (0);
262}
263
264#if 0
265static int
266amdsmb_abort(struct amdsmb_softc *sc)
267{
268	u_short l;
269
270	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
271	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, l | AMDSMB_GE_ABORT);
272
273	return (0);
274}
275#endif
276
277static int
278amdsmb_idle(struct amdsmb_softc *sc)
279{
280	u_short sts;
281
282	sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
283
284	AMDPM_DEBUG(printf("amdpm: busy? STS=0x%x\n", sts));
285
286	return (~(sts & AMDSMB_GS_HST_STS));
287}
288
289/*
290 * Poll the SMBus controller
291 */
292static int
293amdsmb_wait(struct amdsmb_softc *sc)
294{
295	int count = 10000;
296	u_short sts = 0;
297	int error;
298
299	/* Wait for command to complete (SMBus controller is idle) */
300	while(count--) {
301		DELAY(10);
302		sts = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_STATUS);
303		if (!(sts & AMDSMB_GS_HST_STS))
304			break;
305	}
306
307	AMDPM_DEBUG(printf("amdpm: STS=0x%x (count=%d)\n", sts, count));
308
309	error = SMB_ENOERR;
310
311	if (!count)
312		error |= SMB_ETIMEOUT;
313
314	if (sts & AMDSMB_GS_ABRT_STS)
315		error |= SMB_EABORT;
316
317	if (sts & AMDSMB_GS_COL_STS)
318		error |= SMB_ENOACK;
319
320	if (sts & AMDSMB_GS_PRERR_STS)
321		error |= SMB_EBUSERR;
322
323	if (error != SMB_ENOERR)
324		amdsmb_clear(sc);
325
326	return (error);
327}
328
329static int
330amdsmb_smb_quick(device_t dev, u_char slave, int how)
331{
332	struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
333	int error;
334	u_short l;
335
336	amdsmb_clear(sc);
337	if (!amdsmb_idle(sc))
338		return (EBUSY);
339
340	switch (how) {
341	case SMB_QWRITE:
342		AMDPM_DEBUG(printf("amdpm: QWRITE to 0x%x", slave));
343		AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
344		break;
345	case SMB_QREAD:
346		AMDPM_DEBUG(printf("amdpm: QREAD to 0x%x", slave));
347		AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
348		break;
349	default:
350		panic("%s: unknown QUICK command (%x)!", __func__, how);
351	}
352	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
353	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_QUICK | AMDSMB_GE_HOST_STC);
354
355	error = amdsmb_wait(sc);
356
357	AMDPM_DEBUG(printf(", error=0x%x\n", error));
358
359	return (error);
360}
361
362static int
363amdsmb_smb_sendb(device_t dev, u_char slave, char byte)
364{
365	struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
366	int error;
367	u_short l;
368
369	amdsmb_clear(sc);
370	if (!amdsmb_idle(sc))
371		return (SMB_EBUSY);
372
373	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
374	AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
375	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
376	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
377
378	error = amdsmb_wait(sc);
379
380	AMDPM_DEBUG(printf("amdpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
381
382	return (error);
383}
384
385static int
386amdsmb_smb_recvb(device_t dev, u_char slave, char *byte)
387{
388	struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
389	int error;
390	u_short l;
391
392	amdsmb_clear(sc);
393	if (!amdsmb_idle(sc))
394		return (SMB_EBUSY);
395
396	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
397	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
398	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BYTE | AMDSMB_GE_HOST_STC);
399
400	if ((error = amdsmb_wait(sc)) == SMB_ENOERR)
401		*byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
402
403	AMDPM_DEBUG(printf("amdpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
404
405	return (error);
406}
407
408static int
409amdsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte)
410{
411	struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
412	int error;
413	u_short l;
414
415	amdsmb_clear(sc);
416	if (!amdsmb_idle(sc))
417		return (SMB_EBUSY);
418
419	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
420	AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, byte);
421	AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
422	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
423	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
424
425	error = amdsmb_wait(sc);
426
427	AMDPM_DEBUG(printf("amdpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
428
429	return (error);
430}
431
432static int
433amdsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte)
434{
435	struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
436	int error;
437	u_short l;
438
439	amdsmb_clear(sc);
440	if (!amdsmb_idle(sc))
441		return (SMB_EBUSY);
442
443	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
444	AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
445	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
446	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BDATA | AMDSMB_GE_HOST_STC);
447
448	if ((error = amdsmb_wait(sc)) == SMB_ENOERR)
449		*byte = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
450
451	AMDPM_DEBUG(printf("amdpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
452
453	return (error);
454}
455
456static int
457amdsmb_smb_writew(device_t dev, u_char slave, char cmd, short word)
458{
459	struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
460	int error;
461	u_short l;
462
463	amdsmb_clear(sc);
464	if (!amdsmb_idle(sc))
465		return (SMB_EBUSY);
466
467	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
468	AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, word);
469	AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
470	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
471	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
472
473	error = amdsmb_wait(sc);
474
475	AMDPM_DEBUG(printf("amdpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
476
477	return (error);
478}
479
480static int
481amdsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word)
482{
483	struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
484	int error;
485	u_short l;
486
487	amdsmb_clear(sc);
488	if (!amdsmb_idle(sc))
489		return (SMB_EBUSY);
490
491	AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
492	AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
493	l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
494	AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_WDATA | AMDSMB_GE_HOST_STC);
495
496	if ((error = amdsmb_wait(sc)) == SMB_ENOERR)
497		*word = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
498
499	AMDPM_DEBUG(printf("amdpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
500
501	return (error);
502}
503
504static int
505amdsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
506{
507	struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
508	u_char remain, len, i;
509	int error = SMB_ENOERR;
510	u_short l;
511
512	amdsmb_clear(sc);
513	if(!amdsmb_idle(sc))
514		return (SMB_EBUSY);
515
516	remain = count;
517	while (remain) {
518		len = min(remain, 32);
519
520		AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave & ~LSB);
521
522		/*
523		 * Do we have to reset the internal 32-byte buffer?
524		 * Can't see how to do this from the data sheet.
525		 */
526
527		AMDPM_SMBOUTW(sc, AMDSMB_HSTDATA, len);
528
529		/* Fill the 32-byte internal buffer */
530		for (i=0; i<len; i++) {
531			AMDPM_SMBOUTB(sc, AMDSMB_HSTDFIFO, buf[count-remain+i]);
532			DELAY(2);
533		}
534		AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
535		l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
536		AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
537
538		if ((error = amdsmb_wait(sc)) != SMB_ENOERR)
539			goto error;
540
541		remain -= len;
542	}
543
544error:
545	AMDPM_DEBUG(printf("amdpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
546
547	return (error);
548}
549
550static int
551amdsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
552{
553	struct amdsmb_softc *sc = (struct amdsmb_softc *)device_get_softc(dev);
554	u_char remain, len, i;
555	int error = SMB_ENOERR;
556	u_short l;
557
558	amdsmb_clear(sc);
559	if (!amdsmb_idle(sc))
560		return (SMB_EBUSY);
561
562	remain = count;
563	while (remain) {
564		AMDPM_SMBOUTW(sc, AMDSMB_HSTADDR, slave | LSB);
565
566		AMDPM_SMBOUTB(sc, AMDSMB_HSTCMD, cmd);
567
568		l = AMDPM_SMBINW(sc, AMDSMB_GLOBAL_ENABLE);
569		AMDPM_SMBOUTW(sc, AMDSMB_GLOBAL_ENABLE, (l & 0xfff8) | AMDSMB_GE_CYC_BLOCK | AMDSMB_GE_HOST_STC);
570
571		if ((error = amdsmb_wait(sc)) != SMB_ENOERR)
572			goto error;
573
574		len = AMDPM_SMBINW(sc, AMDSMB_HSTDATA);
575
576		/* Read the 32-byte internal buffer */
577		for (i=0; i<len; i++) {
578			buf[count-remain+i] = AMDPM_SMBINB(sc, AMDSMB_HSTDFIFO);
579			DELAY(2);
580		}
581
582		remain -= len;
583	}
584error:
585	AMDPM_DEBUG(printf("amdpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
586
587	return (error);
588}
589
590static devclass_t amdpm_devclass;
591
592static device_method_t amdpm_methods[] = {
593	/* Device interface */
594	DEVMETHOD(device_probe,		amdpm_probe),
595	DEVMETHOD(device_attach,	amdpm_attach),
596
597	{ 0, 0 }
598};
599
600static driver_t amdpm_driver = {
601	"amdpm",
602	amdpm_methods,
603	sizeof(struct amdpm_softc),
604};
605
606static devclass_t amdsmb_devclass;
607
608static device_method_t amdsmb_methods[] = {
609	/* Device interface */
610	DEVMETHOD(device_probe,		amdsmb_probe),
611	DEVMETHOD(device_attach,	amdsmb_attach),
612
613	/* Bus interface */
614	DEVMETHOD(bus_print_child,	bus_generic_print_child),
615
616	/* SMBus interface */
617	DEVMETHOD(smbus_callback,	amdsmb_smb_callback),
618	DEVMETHOD(smbus_quick,		amdsmb_smb_quick),
619	DEVMETHOD(smbus_sendb,		amdsmb_smb_sendb),
620	DEVMETHOD(smbus_recvb,		amdsmb_smb_recvb),
621	DEVMETHOD(smbus_writeb,		amdsmb_smb_writeb),
622	DEVMETHOD(smbus_readb,		amdsmb_smb_readb),
623	DEVMETHOD(smbus_writew,		amdsmb_smb_writew),
624	DEVMETHOD(smbus_readw,		amdsmb_smb_readw),
625	DEVMETHOD(smbus_bwrite,		amdsmb_smb_bwrite),
626	DEVMETHOD(smbus_bread,		amdsmb_smb_bread),
627
628	{ 0, 0 }
629};
630
631static driver_t amdsmb_driver = {
632	"amdsmb",
633	amdsmb_methods,
634	sizeof(struct amdsmb_softc),
635};
636
637DRIVER_MODULE(amdpm, pci, amdpm_driver, amdpm_devclass, 0, 0);
638DRIVER_MODULE(amdsmb, amdpm, amdsmb_driver, amdsmb_devclass, 0, 0);
639MODULE_DEPEND(amdpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
640MODULE_VERSION(amdpm, 1);
641