Initial import from FreeBSD RELENG_4:
[games.git] / sys / dev / powermng / i386 / viapm / viapm.c
1 /*-
2  * Copyright (c) 2001 Alcove - Nicolas Souchu
3  * Copyright (c) 2002 Nicolas Souchu
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD: src/sys/pci/viapm.c,v 1.1.2.1 2002/04/19 05:52:15 nsouch Exp $
28  *
29  */
30 #include <sys/param.h>
31 #include <sys/kernel.h>
32 #include <sys/systm.h>
33 #include <sys/module.h>
34 #include <sys/bus.h>
35 #include <sys/uio.h>
36
37 #include <machine/bus_pio.h>
38 #include <machine/bus_memio.h>
39 #include <machine/bus.h>
40 #include <machine/clock.h>              /* for DELAY */
41 #include <machine/resource.h>
42 #include <sys/rman.h>
43
44 #include <pci/pcivar.h>
45 #include <pci/pcireg.h>
46
47 #include <dev/iicbus/iiconf.h>
48 #include <dev/iicbus/iicbus.h>
49
50 #include <dev/smbus/smbconf.h>
51 #include <dev/smbus/smbus.h>
52
53 #include "iicbb_if.h"
54 #include "smbus_if.h"
55
56 #define VIAPM_DEBUG(x)  if (viapm_debug) (x)
57
58 #ifdef DEBUG
59 static int viapm_debug = 1;
60 #else
61 static int viapm_debug = 0;
62 #endif
63
64 #define VIA_586B_PMU_ID         0x30401106
65 #define VIA_596A_PMU_ID         0x30501106
66 #define VIA_596B_PMU_ID         0x30511106
67 #define VIA_686A_PMU_ID         0x30571106
68 #define VIA_8233_PMU_ID         0x30741106
69
70 #define VIAPM_INB(port) \
71         ((u_char)bus_space_read_1(viapm->st, viapm->sh, port))
72 #define VIAPM_OUTB(port,val) \
73         (bus_space_write_1(viapm->st, viapm->sh, port, (u_char)val))
74
75 #define VIAPM_TYP_UNKNOWN       0
76 #define VIAPM_TYP_586B_3040E    1
77 #define VIAPM_TYP_586B_3040F    2
78 #define VIAPM_TYP_596B          3
79 #define VIAPM_TYP_686A          4
80 #define VIAPM_TYP_8233          5
81
82 struct viapm_softc {
83         int type;
84         u_int32_t base;
85         bus_space_tag_t st;
86         bus_space_handle_t sh;
87         int iorid;
88         int irqrid;
89         struct resource *iores;
90         struct resource *irqres;
91         void *irqih;
92
93         device_t iicbb;
94         device_t smbus;
95 };
96
97 static devclass_t viapm_devclass;
98 static devclass_t viapropm_devclass;
99
100 /*
101  * VT82C586B definitions
102  */
103
104 #define VIAPM_586B_REVID        0x08
105
106 #define VIAPM_586B_3040E_BASE   0x20
107 #define VIAPM_586B_3040E_ACTIV  0x4             /* 16 bits */
108
109 #define VIAPM_586B_3040F_BASE   0x48
110 #define VIAPM_586B_3040F_ACTIV  0x41            /* 8 bits */
111
112 #define VIAPM_586B_OEM_REV_E    0x00
113 #define VIAPM_586B_OEM_REV_F    0x01
114 #define VIAPM_586B_PROD_REV_A   0x10
115
116 #define VIAPM_586B_BA_MASK      0x0000ff00
117
118 #define GPIO_DIR        0x40
119 #define GPIO_VAL        0x42
120 #define EXTSMI_VAL      0x44
121
122 #define VIAPM_SCL       0x02                    /* GPIO1_VAL */
123 #define VIAPM_SDA       0x04                    /* GPIO2_VAL */
124
125 /*
126  * VIAPRO common definitions
127  */
128
129 #define VIAPM_PRO_BA_MASK       0x0000fff0
130 #define VIAPM_PRO_SMBCTRL       0xd2
131 #define VIAPM_PRO_REVID         0xd6
132
133 /*
134  * VT82C686A definitions
135  */
136
137 #define VIAPM_PRO_BASE          0x90
138
139 #define SMBHST                  0x0
140 #define SMBHSL                  0x1
141 #define SMBHCTRL                0x2
142 #define SMBHCMD                 0x3
143 #define SMBHADDR                0x4
144 #define SMBHDATA0               0x5
145 #define SMBHDATA1               0x6
146 #define SMBHBLOCK               0x7
147
148 #define SMBSST                  0x1
149 #define SMBSCTRL                0x8
150 #define SMBSSDWCMD              0x9
151 #define SMBSEVENT               0xa
152 #define SMBSDATA                0xc
153
154 #define SMBHST_RESERVED         0xef    /* reserved bits */
155 #define SMBHST_FAILED           0x10    /* failed bus transaction */
156 #define SMBHST_COLLID           0x08    /* bus collision */
157 #define SMBHST_ERROR            0x04    /* device error */
158 #define SMBHST_INTR             0x02    /* command completed */
159 #define SMBHST_BUSY             0x01    /* host busy */
160
161 #define SMBHCTRL_START          0x40    /* start command */
162 #define SMBHCTRL_PROTO          0x1c    /* command protocol mask */
163 #define SMBHCTRL_QUICK          0x00
164 #define SMBHCTRL_SENDRECV       0x04
165 #define SMBHCTRL_BYTE           0x08
166 #define SMBHCTRL_WORD           0x0c
167 #define SMBHCTRL_BLOCK          0x14
168 #define SMBHCTRL_KILL           0x02    /* stop the current transaction */
169 #define SMBHCTRL_ENABLE         0x01    /* enable interrupts */
170
171 #define SMBSCTRL_ENABLE         0x01    /* enable slave */
172
173
174 /*
175  * VIA8233 definitions
176  */
177
178 #define VIAPM_8233_BASE         0xD0
179
180 static int
181 viapm_586b_probe(device_t dev)
182 {
183         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
184         u_int32_t l;
185         u_int16_t s;
186         u_int8_t c;
187
188         switch (pci_get_devid(dev)) {
189         case VIA_586B_PMU_ID:
190
191                 bzero(viapm, sizeof(struct viapm_softc));
192
193                 l = pci_read_config(dev, VIAPM_586B_REVID, 1);
194                 switch (l) {
195                 case VIAPM_586B_OEM_REV_E:
196                         viapm->type = VIAPM_TYP_586B_3040E;
197                         viapm->iorid = VIAPM_586B_3040E_BASE;
198
199                         /* Activate IO block access */
200                         s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2);
201                         pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2);
202                         break;
203
204                 case VIAPM_586B_OEM_REV_F:
205                 case VIAPM_586B_PROD_REV_A:
206                 default:
207                         viapm->type = VIAPM_TYP_586B_3040F;
208                         viapm->iorid = VIAPM_586B_3040F_BASE;
209
210                         /* Activate IO block access */
211                         c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1);
212                         pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1);
213                         break;
214                 }
215
216                 viapm->base = pci_read_config(dev, viapm->iorid, 4) &
217                                 VIAPM_586B_BA_MASK;
218
219                 /*
220                  * We have to set the I/O resources by hand because it is
221                  * described outside the viapmope of the traditional maps
222                  */
223                 if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
224                                                         viapm->base, 256)) {
225                         device_printf(dev, "could not set bus resource\n");
226                         return ENXIO;
227                 }
228                 device_set_desc(dev, "VIA VT82C586B Power Management Unit");
229                 return 0;
230
231         default:
232                 break;
233         }
234
235         return ENXIO;
236 }
237
238
239 static int
240 viapm_pro_probe(device_t dev)
241 {
242         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
243 #ifdef VIAPM_BASE_ADDR
244         u_int32_t l;
245 #endif
246         u_int32_t base_cfgreg;
247         char *desc;
248
249         switch (pci_get_devid(dev)) {
250         case VIA_596A_PMU_ID:
251                 desc = "VIA VT82C596A Power Management Unit";
252                 viapm->type = VIAPM_TYP_596B;
253                 base_cfgreg = VIAPM_PRO_BASE;
254                 goto viapro;
255
256         case VIA_596B_PMU_ID:
257                 desc = "VIA VT82C596B Power Management Unit";
258                 viapm->type = VIAPM_TYP_596B;
259                 base_cfgreg = VIAPM_PRO_BASE;
260                 goto viapro;
261
262         case VIA_686A_PMU_ID:
263                 desc = "VIA VT82C686A Power Management Unit";
264                 viapm->type = VIAPM_TYP_686A;
265                 base_cfgreg = VIAPM_PRO_BASE;
266                 goto viapro;
267
268         case VIA_8233_PMU_ID:
269                 desc = "VIA VT8233 Power Management Unit";
270                 viapm->type = VIAPM_TYP_UNKNOWN;
271                 base_cfgreg = VIAPM_8233_BASE;
272                 goto viapro;
273
274         viapro:
275
276 #ifdef VIAPM_BASE_ADDR
277                 /* force VIAPM I/O base address */
278
279                 /* enable the SMBus controller function */
280                 l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
281                 pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
282
283                 /* write the base address */
284                 pci_write_config(dev, base_cfgreg,
285                                  VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4);
286 #endif
287
288                 viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK;
289
290                 /*
291                  * We have to set the I/O resources by hand because it is
292                  * described outside the viapmope of the traditional maps
293                  */
294                 viapm->iorid = base_cfgreg;
295                 if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
296                                      viapm->base, 16)) {
297                         device_printf(dev, "could not set bus resource 0x%x\n",
298                                         viapm->base);
299                         return ENXIO;
300                 }
301
302                 if (1 || bootverbose) {
303                         device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base);
304                 }
305
306                 device_set_desc(dev, desc);
307                 return 0;
308
309         default:
310                 break;
311         }
312
313         return ENXIO;
314 }
315
316 static int
317 viapm_pro_attach(device_t dev)
318 {
319         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
320         u_int32_t l;
321
322         if (!(viapm->iores = bus_alloc_resource(dev, SYS_RES_IOPORT,
323                 &viapm->iorid, 0l, ~0l, 1, RF_ACTIVE))) {
324                 device_printf(dev, "could not allocate bus space\n");
325                 goto error;
326         }
327         viapm->st = rman_get_bustag(viapm->iores);
328         viapm->sh = rman_get_bushandle(viapm->iores);
329
330 #if notyet
331         /* force irq 9 */
332         l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
333         pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1);
334
335         viapm->irqrid = 0;
336         if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ,
337                                 &viapm->irqrid, 9, 9, 1,
338                                 RF_SHAREABLE | RF_ACTIVE))) {
339                 device_printf(dev, "could not allocate irq\n");
340                 goto error;
341         }
342
343         if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC,
344                         (driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) {
345                 device_printf(dev, "could not setup irq\n");
346                 goto error;
347         }
348 #endif
349
350         if (1 | bootverbose) {
351                 l = pci_read_config(dev, VIAPM_PRO_REVID, 1);
352                 device_printf(dev, "SMBus revision code 0x%x\n", l);
353         }
354
355         viapm->smbus = device_add_child(dev, "smbus", -1);
356
357         /* probe and attach the smbus */
358         bus_generic_attach(dev);
359
360         /* disable slave function */
361         VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE);
362
363         /* enable the SMBus controller function */
364         l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
365         pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
366
367 #if notyet
368         /* enable interrupts */
369         VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE);
370 #endif
371
372         return 0;
373
374 error:
375         if (viapm->iores)
376                 bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores);
377 #if notyet
378         if (viapm->irqres)
379                 bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres);
380 #endif
381
382         return ENXIO;
383 }
384
385 static int
386 viapm_586b_attach(device_t dev)
387 {
388         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
389         
390         if (!(viapm->iores = bus_alloc_resource(dev, SYS_RES_IOPORT,
391                 &viapm->iorid, 0ul, ~0ul, 1, RF_ACTIVE | RF_SHAREABLE))) {
392                 device_printf(dev, "could not allocate bus resource\n");
393                 return ENXIO;
394         }
395         viapm->st = rman_get_bustag(viapm->iores);
396         viapm->sh = rman_get_bushandle(viapm->iores);
397
398         VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA);
399
400         /* add generic bit-banging code */
401         if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1)))
402                 goto error;
403
404         bus_generic_attach(dev);
405
406         return 0;
407
408 error:
409         if (viapm->iores)
410                 bus_release_resource(dev, SYS_RES_IOPORT,
411                                         viapm->iorid, viapm->iores);
412         return ENXIO;
413 }
414
415 static int
416 viapm_586b_detach(device_t dev)
417 {
418         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
419         int error;
420
421         bus_generic_detach(dev);
422         if (viapm->iicbb) {
423                 device_delete_child(dev, viapm->iicbb);
424         }
425
426         if (viapm->iores && (error = bus_release_resource(dev, SYS_RES_IOPORT,
427                                                 viapm->iorid, viapm->iores)))
428                 return (error);
429
430         return 0;
431 }
432
433 static int
434 viapm_pro_detach(device_t dev)
435 {
436         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
437         int error;
438
439         bus_generic_detach(dev);
440         if (viapm->smbus) {
441                 device_delete_child(dev, viapm->smbus);
442         }
443
444         if ((error = bus_release_resource(dev, SYS_RES_IOPORT,
445                                 viapm->iorid, viapm->iores)))
446                 return (error);
447
448 #if notyet
449         if ((error = bus_release_resource(dev, SYS_RES_IRQ,
450                                         viapm->irqrid, viapm->irqres))
451                 return (error);
452 #endif
453
454         return 0;
455 }
456
457 static int
458 viabb_callback(device_t dev, int index, caddr_t *data)
459 {
460         return 0;
461 }
462
463 static void
464 viabb_setscl(device_t dev, int ctrl)
465 {
466         struct viapm_softc *viapm = device_get_softc(dev);
467         u_char val;
468
469         val = VIAPM_INB(GPIO_VAL);
470
471         if (ctrl)
472                 val |= VIAPM_SCL;
473         else
474                 val &= ~VIAPM_SCL;
475
476         VIAPM_OUTB(GPIO_VAL, val);
477
478         return;
479 }
480
481 static void
482 viabb_setsda(device_t dev, int data)
483 {
484         struct viapm_softc *viapm = device_get_softc(dev);
485         u_char val;
486
487         val = VIAPM_INB(GPIO_VAL);
488
489         if (data)
490                 val |= VIAPM_SDA;
491         else
492                 val &= ~VIAPM_SDA;
493
494         VIAPM_OUTB(GPIO_VAL, val);
495
496         return;
497 }
498         
499 static int
500 viabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
501 {
502         /* reset bus */
503         viabb_setsda(dev, 1);
504         viabb_setscl(dev, 1);
505
506         return (IIC_ENOADDR);
507 }
508
509 #if 0
510 static int
511 viabb_getscl(device_t dev)
512 {
513         struct viapm_softc *viapm = device_get_softc(dev);
514
515         return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SCL) != 0);
516 }
517 #endif
518
519 static int
520 viabb_getsda(device_t dev)
521 {
522         struct viapm_softc *viapm = device_get_softc(dev);
523
524         return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SDA) != 0);
525 }
526
527 static void
528 viabb_setlines(device_t dev, int ctrl, int data)
529 {
530         viabb_setscl(dev, ctrl);
531         viabb_setsda(dev, data);
532
533         return;
534 }
535
536 static int
537 viapm_abort(struct viapm_softc *viapm)
538 {
539         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL);
540         DELAY(10);
541
542         return (0);
543 }
544
545 static int
546 viapm_clear(struct viapm_softc *viapm)
547 {
548         VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID |
549                 SMBHST_ERROR | SMBHST_INTR);
550         DELAY(10);
551
552         return (0);
553 }
554
555 static int
556 viapm_busy(struct viapm_softc *viapm)
557 {
558         u_char sts;
559
560         sts = VIAPM_INB(SMBHST);
561
562         VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts));
563
564         return (sts & SMBHST_BUSY);
565 }
566
567 /*
568  * Poll the SMBus controller
569  */
570 static int
571 viapm_wait(struct viapm_softc *viapm)
572 {
573         int count = 10000;
574         u_char sts = 0;
575         int error;
576
577         /* wait for command to complete and SMBus controller is idle */
578         while(count--) {
579                 DELAY(10);
580                 sts = VIAPM_INB(SMBHST);
581
582                 /* check if the controller is processing a command */
583                 if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR))
584                         break;
585         }
586
587         VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts));
588
589         error = SMB_ENOERR;
590
591         if (!count)
592                 error |= SMB_ETIMEOUT;
593
594         if (sts & SMBHST_FAILED)
595                 error |= SMB_EABORT;
596
597         if (sts & SMBHST_COLLID)
598                 error |= SMB_ENOACK;
599
600         if (sts & SMBHST_ERROR)
601                 error |= SMB_EBUSERR;
602
603         if (error != SMB_ENOERR)
604                 viapm_abort(viapm);
605
606         viapm_clear(viapm);
607
608         return (error);
609 }
610
611 static int
612 viasmb_callback(device_t dev, int index, caddr_t *data)
613 {
614         int error = 0;
615
616         switch (index) {
617         case SMB_REQUEST_BUS:
618         case SMB_RELEASE_BUS:
619                 /* ok, bus allocation accepted */
620                 break;
621         default:
622                 error = EINVAL;
623         }
624
625         return (error);
626 }
627
628 static int
629 viasmb_quick(device_t dev, u_char slave, int how)
630 {
631         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
632         int error;
633
634         viapm_clear(viapm);
635         if (viapm_busy(viapm))
636                 return (EBUSY);
637
638         switch (how) {
639         case SMB_QWRITE:
640                 VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave));
641                 VIAPM_OUTB(SMBHADDR, slave & ~LSB);
642                 break;
643         case SMB_QREAD:
644                 VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave));
645                 VIAPM_OUTB(SMBHADDR, slave | LSB);
646                 break;
647         default:
648                 panic("%s: unknown QUICK command (%x)!", __FUNCTION__,
649                         how);
650         }
651
652         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK);
653
654         error = viapm_wait(viapm);
655
656         return (error);
657 }
658
659 static int
660 viasmb_sendb(device_t dev, u_char slave, char byte)
661 {
662         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
663         int error;
664
665         viapm_clear(viapm);
666         if (viapm_busy(viapm))
667                 return (EBUSY);
668
669         VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
670         VIAPM_OUTB(SMBHCMD, byte);
671
672         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
673
674         error = viapm_wait(viapm);
675
676         VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
677
678         return (error);
679 }
680
681 static int
682 viasmb_recvb(device_t dev, u_char slave, char *byte)
683 {
684         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
685         int error;
686
687         viapm_clear(viapm);
688         if (viapm_busy(viapm))
689                 return (EBUSY);
690
691         VIAPM_OUTB(SMBHADDR, slave | LSB);
692
693         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
694
695         if ((error = viapm_wait(viapm)) == SMB_ENOERR)
696                 *byte = VIAPM_INB(SMBHDATA0);
697
698         VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
699
700         return (error);
701 }
702
703 static int
704 viasmb_writeb(device_t dev, u_char slave, char cmd, char byte)
705 {
706         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
707         int error;
708
709         viapm_clear(viapm);
710         if (viapm_busy(viapm))
711                 return (EBUSY);
712
713         VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
714         VIAPM_OUTB(SMBHCMD, cmd);
715         VIAPM_OUTB(SMBHDATA0, byte);
716
717         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
718
719         error = viapm_wait(viapm);
720
721         VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
722
723         return (error);
724 }
725
726 static int
727 viasmb_readb(device_t dev, u_char slave, char cmd, char *byte)
728 {
729         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
730         int error;
731
732         viapm_clear(viapm);
733         if (viapm_busy(viapm))
734                 return (EBUSY);
735
736         VIAPM_OUTB(SMBHADDR, slave | LSB);
737         VIAPM_OUTB(SMBHCMD, cmd);
738
739         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
740
741         if ((error = viapm_wait(viapm)) == SMB_ENOERR)
742                 *byte = VIAPM_INB(SMBHDATA0);
743
744         VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
745
746         return (error);
747 }
748
749 static int
750 viasmb_writew(device_t dev, u_char slave, char cmd, short word)
751 {
752         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
753         int error;
754
755         viapm_clear(viapm);
756         if (viapm_busy(viapm))
757                 return (EBUSY);
758
759         VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
760         VIAPM_OUTB(SMBHCMD, cmd);
761         VIAPM_OUTB(SMBHDATA0, word & 0x00ff);
762         VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8);
763
764         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
765
766         error = viapm_wait(viapm);
767
768         VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
769
770         return (error);
771 }
772
773 static int
774 viasmb_readw(device_t dev, u_char slave, char cmd, short *word)
775 {
776         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
777         int error;
778         u_char high, low;
779
780         viapm_clear(viapm);
781         if (viapm_busy(viapm))
782                 return (EBUSY);
783
784         VIAPM_OUTB(SMBHADDR, slave | LSB);
785         VIAPM_OUTB(SMBHCMD, cmd);
786
787         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
788
789         if ((error = viapm_wait(viapm)) == SMB_ENOERR) {
790                 low = VIAPM_INB(SMBHDATA0);
791                 high = VIAPM_INB(SMBHDATA1);
792
793                 *word = ((high & 0xff) << 8) | (low & 0xff);
794         }
795
796         VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
797
798         return (error);
799 }
800
801 static int
802 viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
803 {
804         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
805         u_char remain, len, i;
806         int error = SMB_ENOERR;
807
808         viapm_clear(viapm);
809         if (viapm_busy(viapm))
810                 return (EBUSY);
811
812         remain = count;
813         while (remain) {
814                 len = min(remain, 32);
815
816                 VIAPM_OUTB(SMBHADDR, slave & ~LSB);
817                 VIAPM_OUTB(SMBHCMD, cmd);
818                 VIAPM_OUTB(SMBHDATA0, len);
819                 i = VIAPM_INB(SMBHCTRL);
820
821                 /* fill the 32-byte internal buffer */
822                 for (i=0; i<len; i++) {
823                         VIAPM_OUTB(SMBHBLOCK, buf[count-remain+i]);
824                         DELAY(2);
825                 }
826                 VIAPM_OUTB(SMBHCMD, cmd);
827                 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
828
829                 if ((error = viapm_wait(viapm)) != SMB_ENOERR)
830                         goto error;
831
832                 remain -= len;
833         }
834
835 error:
836         VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
837
838         return (error);
839
840 }
841
842 static int
843 viasmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
844 {
845         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
846         u_char remain, len, i;
847         int error = SMB_ENOERR;
848
849         viapm_clear(viapm);
850         if (viapm_busy(viapm))
851                 return (EBUSY);
852
853         remain = count;
854         while (remain) {
855                 VIAPM_OUTB(SMBHADDR, slave | LSB);
856                 VIAPM_OUTB(SMBHCMD, cmd);
857                 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
858
859                 if ((error = viapm_wait(viapm)) != SMB_ENOERR)
860                         goto error;
861
862                 len = VIAPM_INB(SMBHDATA0);
863                 i = VIAPM_INB(SMBHCTRL);                /* reset counter */
864
865                 len = min(len, remain);
866
867                 /* read the 32-byte internal buffer */
868                 for (i=0; i<len; i++) {
869                         buf[count-remain+i] = VIAPM_INB(SMBHBLOCK);
870                         DELAY(2);
871                 }
872
873                 remain -= len;
874         }
875 error:
876         VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
877
878         return (error);
879 }
880
881 static device_method_t viapm_methods[] = {
882         /* device interface */
883         DEVMETHOD(device_probe,         viapm_586b_probe),
884         DEVMETHOD(device_attach,        viapm_586b_attach),
885         DEVMETHOD(device_detach,        viapm_586b_detach),
886
887         /* iicbb interface */
888         DEVMETHOD(iicbb_callback,       viabb_callback),
889         DEVMETHOD(iicbb_setlines,       viabb_setlines),
890         DEVMETHOD(iicbb_getdataline,    viabb_getsda),
891         DEVMETHOD(iicbb_reset,          viabb_reset),
892
893         { 0, 0 }
894 };
895
896 static driver_t viapm_driver = {
897         "viapm",
898         viapm_methods,
899         sizeof(struct viapm_softc),
900 };
901
902 static device_method_t viapropm_methods[] = {
903         /* device interface */
904         DEVMETHOD(device_probe,         viapm_pro_probe),
905         DEVMETHOD(device_attach,        viapm_pro_attach),
906         DEVMETHOD(device_detach,        viapm_pro_detach),
907
908         /* smbus interface */
909         DEVMETHOD(smbus_callback,       viasmb_callback),
910         DEVMETHOD(smbus_quick,          viasmb_quick),
911         DEVMETHOD(smbus_sendb,          viasmb_sendb),
912         DEVMETHOD(smbus_recvb,          viasmb_recvb),
913         DEVMETHOD(smbus_writeb,         viasmb_writeb),
914         DEVMETHOD(smbus_readb,          viasmb_readb),
915         DEVMETHOD(smbus_writew,         viasmb_writew),
916         DEVMETHOD(smbus_readw,          viasmb_readw),
917         DEVMETHOD(smbus_bwrite,         viasmb_bwrite),
918         DEVMETHOD(smbus_bread,          viasmb_bread),
919         
920         { 0, 0 }
921 };
922
923 static driver_t viapropm_driver = {
924         "viapropm",
925         viapropm_methods,
926         sizeof(struct viapm_softc),
927 };
928
929 DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0);
930 DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0);
931
932 MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
933 MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
934 MODULE_VERSION(viapm, 1);