GCC supports two pseudo variables to get the function name, __FUNCTION__
[dragonfly.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  * $DragonFly: src/sys/dev/powermng/i386/viapm/viapm.c,v 1.5 2005/02/17 13:59:36 joerg Exp $
29  *
30  */
31 #include <sys/param.h>
32 #include <sys/kernel.h>
33 #include <sys/systm.h>
34 #include <sys/module.h>
35 #include <sys/bus.h>
36 #include <sys/uio.h>
37
38 #include <machine/bus_pio.h>
39 #include <machine/bus_memio.h>
40 #include <machine/bus.h>
41 #include <machine/clock.h>              /* for DELAY */
42 #include <machine/resource.h>
43 #include <sys/rman.h>
44
45 #include <bus/pci/pcivar.h>
46 #include <bus/pci/pcireg.h>
47
48 #include <bus/iicbus/iiconf.h>
49 #include <bus/iicbus/iicbus.h>
50
51 #include <bus/smbus/smbconf.h>
52 #include <bus/smbus/smbus.h>
53
54 #include "iicbb_if.h"
55 #include "smbus_if.h"
56
57 #define VIAPM_DEBUG(x)  if (viapm_debug) (x)
58
59 #ifdef DEBUG
60 static int viapm_debug = 1;
61 #else
62 static int viapm_debug = 0;
63 #endif
64
65 #define VIA_586B_PMU_ID         0x30401106
66 #define VIA_596A_PMU_ID         0x30501106
67 #define VIA_596B_PMU_ID         0x30511106
68 #define VIA_686A_PMU_ID         0x30571106
69 #define VIA_8233_PMU_ID         0x30741106
70
71 #define VIAPM_INB(port) \
72         ((u_char)bus_space_read_1(viapm->st, viapm->sh, port))
73 #define VIAPM_OUTB(port,val) \
74         (bus_space_write_1(viapm->st, viapm->sh, port, (u_char)val))
75
76 #define VIAPM_TYP_UNKNOWN       0
77 #define VIAPM_TYP_586B_3040E    1
78 #define VIAPM_TYP_586B_3040F    2
79 #define VIAPM_TYP_596B          3
80 #define VIAPM_TYP_686A          4
81 #define VIAPM_TYP_8233          5
82
83 struct viapm_softc {
84         int type;
85         u_int32_t base;
86         bus_space_tag_t st;
87         bus_space_handle_t sh;
88         int iorid;
89         int irqrid;
90         struct resource *iores;
91         struct resource *irqres;
92         void *irqih;
93
94         device_t iicbb;
95         device_t smbus;
96 };
97
98 static devclass_t viapm_devclass;
99 static devclass_t viapropm_devclass;
100
101 /*
102  * VT82C586B definitions
103  */
104
105 #define VIAPM_586B_REVID        0x08
106
107 #define VIAPM_586B_3040E_BASE   0x20
108 #define VIAPM_586B_3040E_ACTIV  0x4             /* 16 bits */
109
110 #define VIAPM_586B_3040F_BASE   0x48
111 #define VIAPM_586B_3040F_ACTIV  0x41            /* 8 bits */
112
113 #define VIAPM_586B_OEM_REV_E    0x00
114 #define VIAPM_586B_OEM_REV_F    0x01
115 #define VIAPM_586B_PROD_REV_A   0x10
116
117 #define VIAPM_586B_BA_MASK      0x0000ff00
118
119 #define GPIO_DIR        0x40
120 #define GPIO_VAL        0x42
121 #define EXTSMI_VAL      0x44
122
123 #define VIAPM_SCL       0x02                    /* GPIO1_VAL */
124 #define VIAPM_SDA       0x04                    /* GPIO2_VAL */
125
126 /*
127  * VIAPRO common definitions
128  */
129
130 #define VIAPM_PRO_BA_MASK       0x0000fff0
131 #define VIAPM_PRO_SMBCTRL       0xd2
132 #define VIAPM_PRO_REVID         0xd6
133
134 /*
135  * VT82C686A definitions
136  */
137
138 #define VIAPM_PRO_BASE          0x90
139
140 #define SMBHST                  0x0
141 #define SMBHSL                  0x1
142 #define SMBHCTRL                0x2
143 #define SMBHCMD                 0x3
144 #define SMBHADDR                0x4
145 #define SMBHDATA0               0x5
146 #define SMBHDATA1               0x6
147 #define SMBHBLOCK               0x7
148
149 #define SMBSST                  0x1
150 #define SMBSCTRL                0x8
151 #define SMBSSDWCMD              0x9
152 #define SMBSEVENT               0xa
153 #define SMBSDATA                0xc
154
155 #define SMBHST_RESERVED         0xef    /* reserved bits */
156 #define SMBHST_FAILED           0x10    /* failed bus transaction */
157 #define SMBHST_COLLID           0x08    /* bus collision */
158 #define SMBHST_ERROR            0x04    /* device error */
159 #define SMBHST_INTR             0x02    /* command completed */
160 #define SMBHST_BUSY             0x01    /* host busy */
161
162 #define SMBHCTRL_START          0x40    /* start command */
163 #define SMBHCTRL_PROTO          0x1c    /* command protocol mask */
164 #define SMBHCTRL_QUICK          0x00
165 #define SMBHCTRL_SENDRECV       0x04
166 #define SMBHCTRL_BYTE           0x08
167 #define SMBHCTRL_WORD           0x0c
168 #define SMBHCTRL_BLOCK          0x14
169 #define SMBHCTRL_KILL           0x02    /* stop the current transaction */
170 #define SMBHCTRL_ENABLE         0x01    /* enable interrupts */
171
172 #define SMBSCTRL_ENABLE         0x01    /* enable slave */
173
174
175 /*
176  * VIA8233 definitions
177  */
178
179 #define VIAPM_8233_BASE         0xD0
180
181 static int
182 viapm_586b_probe(device_t dev)
183 {
184         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
185         u_int32_t l;
186         u_int16_t s;
187         u_int8_t c;
188
189         switch (pci_get_devid(dev)) {
190         case VIA_586B_PMU_ID:
191
192                 bzero(viapm, sizeof(struct viapm_softc));
193
194                 l = pci_read_config(dev, VIAPM_586B_REVID, 1);
195                 switch (l) {
196                 case VIAPM_586B_OEM_REV_E:
197                         viapm->type = VIAPM_TYP_586B_3040E;
198                         viapm->iorid = VIAPM_586B_3040E_BASE;
199
200                         /* Activate IO block access */
201                         s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2);
202                         pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2);
203                         break;
204
205                 case VIAPM_586B_OEM_REV_F:
206                 case VIAPM_586B_PROD_REV_A:
207                 default:
208                         viapm->type = VIAPM_TYP_586B_3040F;
209                         viapm->iorid = VIAPM_586B_3040F_BASE;
210
211                         /* Activate IO block access */
212                         c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1);
213                         pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1);
214                         break;
215                 }
216
217                 viapm->base = pci_read_config(dev, viapm->iorid, 4) &
218                                 VIAPM_586B_BA_MASK;
219
220                 /*
221                  * We have to set the I/O resources by hand because it is
222                  * described outside the viapmope of the traditional maps
223                  */
224                 if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
225                                                         viapm->base, 256)) {
226                         device_printf(dev, "could not set bus resource\n");
227                         return ENXIO;
228                 }
229                 device_set_desc(dev, "VIA VT82C586B Power Management Unit");
230                 return 0;
231
232         default:
233                 break;
234         }
235
236         return ENXIO;
237 }
238
239
240 static int
241 viapm_pro_probe(device_t dev)
242 {
243         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
244 #ifdef VIAPM_BASE_ADDR
245         u_int32_t l;
246 #endif
247         u_int32_t base_cfgreg;
248         char *desc;
249
250         switch (pci_get_devid(dev)) {
251         case VIA_596A_PMU_ID:
252                 desc = "VIA VT82C596A Power Management Unit";
253                 viapm->type = VIAPM_TYP_596B;
254                 base_cfgreg = VIAPM_PRO_BASE;
255                 goto viapro;
256
257         case VIA_596B_PMU_ID:
258                 desc = "VIA VT82C596B Power Management Unit";
259                 viapm->type = VIAPM_TYP_596B;
260                 base_cfgreg = VIAPM_PRO_BASE;
261                 goto viapro;
262
263         case VIA_686A_PMU_ID:
264                 desc = "VIA VT82C686A Power Management Unit";
265                 viapm->type = VIAPM_TYP_686A;
266                 base_cfgreg = VIAPM_PRO_BASE;
267                 goto viapro;
268
269         case VIA_8233_PMU_ID:
270                 desc = "VIA VT8233 Power Management Unit";
271                 viapm->type = VIAPM_TYP_UNKNOWN;
272                 base_cfgreg = VIAPM_8233_BASE;
273                 goto viapro;
274
275         viapro:
276
277 #ifdef VIAPM_BASE_ADDR
278                 /* force VIAPM I/O base address */
279
280                 /* enable the SMBus controller function */
281                 l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
282                 pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
283
284                 /* write the base address */
285                 pci_write_config(dev, base_cfgreg,
286                                  VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4);
287 #endif
288
289                 viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK;
290
291                 /*
292                  * We have to set the I/O resources by hand because it is
293                  * described outside the viapmope of the traditional maps
294                  */
295                 viapm->iorid = base_cfgreg;
296                 if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid,
297                                      viapm->base, 16)) {
298                         device_printf(dev, "could not set bus resource 0x%x\n",
299                                         viapm->base);
300                         return ENXIO;
301                 }
302
303                 if (1 || bootverbose) {
304                         device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base);
305                 }
306
307                 device_set_desc(dev, desc);
308                 return 0;
309
310         default:
311                 break;
312         }
313
314         return ENXIO;
315 }
316
317 static int
318 viapm_pro_attach(device_t dev)
319 {
320         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
321         u_int32_t l;
322
323         if (!(viapm->iores = bus_alloc_resource(dev, SYS_RES_IOPORT,
324                 &viapm->iorid, 0l, ~0l, 1, RF_ACTIVE))) {
325                 device_printf(dev, "could not allocate bus space\n");
326                 goto error;
327         }
328         viapm->st = rman_get_bustag(viapm->iores);
329         viapm->sh = rman_get_bushandle(viapm->iores);
330
331 #if notyet
332         /* force irq 9 */
333         l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
334         pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1);
335
336         viapm->irqrid = 0;
337         if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ,
338                                 &viapm->irqrid, 9, 9, 1,
339                                 RF_SHAREABLE | RF_ACTIVE))) {
340                 device_printf(dev, "could not allocate irq\n");
341                 goto error;
342         }
343
344         if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC,
345                         (driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) {
346                 device_printf(dev, "could not setup irq\n");
347                 goto error;
348         }
349 #endif
350
351         if (1 | bootverbose) {
352                 l = pci_read_config(dev, VIAPM_PRO_REVID, 1);
353                 device_printf(dev, "SMBus revision code 0x%x\n", l);
354         }
355
356         viapm->smbus = device_add_child(dev, "smbus", -1);
357
358         /* probe and attach the smbus */
359         bus_generic_attach(dev);
360
361         /* disable slave function */
362         VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE);
363
364         /* enable the SMBus controller function */
365         l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
366         pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
367
368 #if notyet
369         /* enable interrupts */
370         VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE);
371 #endif
372
373         return 0;
374
375 error:
376         if (viapm->iores)
377                 bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores);
378 #if notyet
379         if (viapm->irqres)
380                 bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres);
381 #endif
382
383         return ENXIO;
384 }
385
386 static int
387 viapm_586b_attach(device_t dev)
388 {
389         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
390         
391         if (!(viapm->iores = bus_alloc_resource(dev, SYS_RES_IOPORT,
392                 &viapm->iorid, 0ul, ~0ul, 1, RF_ACTIVE | RF_SHAREABLE))) {
393                 device_printf(dev, "could not allocate bus resource\n");
394                 return ENXIO;
395         }
396         viapm->st = rman_get_bustag(viapm->iores);
397         viapm->sh = rman_get_bushandle(viapm->iores);
398
399         VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA);
400
401         /* add generic bit-banging code */
402         if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1)))
403                 goto error;
404
405         bus_generic_attach(dev);
406
407         return 0;
408
409 error:
410         if (viapm->iores)
411                 bus_release_resource(dev, SYS_RES_IOPORT,
412                                         viapm->iorid, viapm->iores);
413         return ENXIO;
414 }
415
416 static int
417 viapm_586b_detach(device_t dev)
418 {
419         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
420         int error;
421
422         bus_generic_detach(dev);
423         if (viapm->iicbb) {
424                 device_delete_child(dev, viapm->iicbb);
425         }
426
427         if (viapm->iores && (error = bus_release_resource(dev, SYS_RES_IOPORT,
428                                                 viapm->iorid, viapm->iores)))
429                 return (error);
430
431         return 0;
432 }
433
434 static int
435 viapm_pro_detach(device_t dev)
436 {
437         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
438         int error;
439
440         bus_generic_detach(dev);
441         if (viapm->smbus) {
442                 device_delete_child(dev, viapm->smbus);
443         }
444
445         if ((error = bus_release_resource(dev, SYS_RES_IOPORT,
446                                 viapm->iorid, viapm->iores)))
447                 return (error);
448
449 #if notyet
450         if ((error = bus_release_resource(dev, SYS_RES_IRQ,
451                                         viapm->irqrid, viapm->irqres))
452                 return (error);
453 #endif
454
455         return 0;
456 }
457
458 static int
459 viabb_callback(device_t dev, int index, caddr_t *data)
460 {
461         return 0;
462 }
463
464 static void
465 viabb_setscl(device_t dev, int ctrl)
466 {
467         struct viapm_softc *viapm = device_get_softc(dev);
468         u_char val;
469
470         val = VIAPM_INB(GPIO_VAL);
471
472         if (ctrl)
473                 val |= VIAPM_SCL;
474         else
475                 val &= ~VIAPM_SCL;
476
477         VIAPM_OUTB(GPIO_VAL, val);
478
479         return;
480 }
481
482 static void
483 viabb_setsda(device_t dev, int data)
484 {
485         struct viapm_softc *viapm = device_get_softc(dev);
486         u_char val;
487
488         val = VIAPM_INB(GPIO_VAL);
489
490         if (data)
491                 val |= VIAPM_SDA;
492         else
493                 val &= ~VIAPM_SDA;
494
495         VIAPM_OUTB(GPIO_VAL, val);
496
497         return;
498 }
499         
500 static int
501 viabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
502 {
503         /* reset bus */
504         viabb_setsda(dev, 1);
505         viabb_setscl(dev, 1);
506
507         return (IIC_ENOADDR);
508 }
509
510 #if 0
511 static int
512 viabb_getscl(device_t dev)
513 {
514         struct viapm_softc *viapm = device_get_softc(dev);
515
516         return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SCL) != 0);
517 }
518 #endif
519
520 static int
521 viabb_getsda(device_t dev)
522 {
523         struct viapm_softc *viapm = device_get_softc(dev);
524
525         return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SDA) != 0);
526 }
527
528 static void
529 viabb_setlines(device_t dev, int ctrl, int data)
530 {
531         viabb_setscl(dev, ctrl);
532         viabb_setsda(dev, data);
533
534         return;
535 }
536
537 static int
538 viapm_abort(struct viapm_softc *viapm)
539 {
540         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL);
541         DELAY(10);
542
543         return (0);
544 }
545
546 static int
547 viapm_clear(struct viapm_softc *viapm)
548 {
549         VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID |
550                 SMBHST_ERROR | SMBHST_INTR);
551         DELAY(10);
552
553         return (0);
554 }
555
556 static int
557 viapm_busy(struct viapm_softc *viapm)
558 {
559         u_char sts;
560
561         sts = VIAPM_INB(SMBHST);
562
563         VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts));
564
565         return (sts & SMBHST_BUSY);
566 }
567
568 /*
569  * Poll the SMBus controller
570  */
571 static int
572 viapm_wait(struct viapm_softc *viapm)
573 {
574         int count = 10000;
575         u_char sts = 0;
576         int error;
577
578         /* wait for command to complete and SMBus controller is idle */
579         while(count--) {
580                 DELAY(10);
581                 sts = VIAPM_INB(SMBHST);
582
583                 /* check if the controller is processing a command */
584                 if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR))
585                         break;
586         }
587
588         VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts));
589
590         error = SMB_ENOERR;
591
592         if (!count)
593                 error |= SMB_ETIMEOUT;
594
595         if (sts & SMBHST_FAILED)
596                 error |= SMB_EABORT;
597
598         if (sts & SMBHST_COLLID)
599                 error |= SMB_ENOACK;
600
601         if (sts & SMBHST_ERROR)
602                 error |= SMB_EBUSERR;
603
604         if (error != SMB_ENOERR)
605                 viapm_abort(viapm);
606
607         viapm_clear(viapm);
608
609         return (error);
610 }
611
612 static int
613 viasmb_callback(device_t dev, int index, caddr_t *data)
614 {
615         int error = 0;
616
617         switch (index) {
618         case SMB_REQUEST_BUS:
619         case SMB_RELEASE_BUS:
620                 /* ok, bus allocation accepted */
621                 break;
622         default:
623                 error = EINVAL;
624         }
625
626         return (error);
627 }
628
629 static int
630 viasmb_quick(device_t dev, u_char slave, int how)
631 {
632         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
633         int error;
634
635         viapm_clear(viapm);
636         if (viapm_busy(viapm))
637                 return (EBUSY);
638
639         switch (how) {
640         case SMB_QWRITE:
641                 VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave));
642                 VIAPM_OUTB(SMBHADDR, slave & ~LSB);
643                 break;
644         case SMB_QREAD:
645                 VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave));
646                 VIAPM_OUTB(SMBHADDR, slave | LSB);
647                 break;
648         default:
649                 panic("%s: unknown QUICK command (%x)!", __func__, 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 DECLARE_DUMMY_MODULE(viapm);
930 DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0);
931 DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0);
932
933 MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
934 MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
935 MODULE_VERSION(viapm, 1);