Get rid of bus_{disable,enable}_intr(), it wasn't generic enough for
[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.6 2005/05/24 20:59:03 dillon 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         int error;
323
324         if (!(viapm->iores = bus_alloc_resource(dev, SYS_RES_IOPORT,
325                 &viapm->iorid, 0l, ~0l, 1, RF_ACTIVE))) {
326                 device_printf(dev, "could not allocate bus space\n");
327                 goto error;
328         }
329         viapm->st = rman_get_bustag(viapm->iores);
330         viapm->sh = rman_get_bushandle(viapm->iores);
331
332 #if notyet
333         /* force irq 9 */
334         l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
335         pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1);
336
337         viapm->irqrid = 0;
338         if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ,
339                                 &viapm->irqrid, 9, 9, 1,
340                                 RF_SHAREABLE | RF_ACTIVE))) {
341                 device_printf(dev, "could not allocate irq\n");
342                 goto error;
343         }
344
345         error = bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC,
346                                (driver_intr_t *) viasmb_intr, viapm, 
347                                &viapm->irqih, NULL);
348         if (error) {
349                 device_printf(dev, "could not setup irq\n");
350                 goto error;
351         }
352 #endif
353
354         if (1 | bootverbose) {
355                 l = pci_read_config(dev, VIAPM_PRO_REVID, 1);
356                 device_printf(dev, "SMBus revision code 0x%x\n", l);
357         }
358
359         viapm->smbus = device_add_child(dev, "smbus", -1);
360
361         /* probe and attach the smbus */
362         bus_generic_attach(dev);
363
364         /* disable slave function */
365         VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE);
366
367         /* enable the SMBus controller function */
368         l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1);
369         pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1);
370
371 #if notyet
372         /* enable interrupts */
373         VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE);
374 #endif
375
376         return 0;
377
378 error:
379         if (viapm->iores)
380                 bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores);
381 #if notyet
382         if (viapm->irqres)
383                 bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres);
384 #endif
385
386         return ENXIO;
387 }
388
389 static int
390 viapm_586b_attach(device_t dev)
391 {
392         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
393         
394         if (!(viapm->iores = bus_alloc_resource(dev, SYS_RES_IOPORT,
395                 &viapm->iorid, 0ul, ~0ul, 1, RF_ACTIVE | RF_SHAREABLE))) {
396                 device_printf(dev, "could not allocate bus resource\n");
397                 return ENXIO;
398         }
399         viapm->st = rman_get_bustag(viapm->iores);
400         viapm->sh = rman_get_bushandle(viapm->iores);
401
402         VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA);
403
404         /* add generic bit-banging code */
405         if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1)))
406                 goto error;
407
408         bus_generic_attach(dev);
409
410         return 0;
411
412 error:
413         if (viapm->iores)
414                 bus_release_resource(dev, SYS_RES_IOPORT,
415                                         viapm->iorid, viapm->iores);
416         return ENXIO;
417 }
418
419 static int
420 viapm_586b_detach(device_t dev)
421 {
422         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
423         int error;
424
425         bus_generic_detach(dev);
426         if (viapm->iicbb) {
427                 device_delete_child(dev, viapm->iicbb);
428         }
429
430         if (viapm->iores && (error = bus_release_resource(dev, SYS_RES_IOPORT,
431                                                 viapm->iorid, viapm->iores)))
432                 return (error);
433
434         return 0;
435 }
436
437 static int
438 viapm_pro_detach(device_t dev)
439 {
440         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
441         int error;
442
443         bus_generic_detach(dev);
444         if (viapm->smbus) {
445                 device_delete_child(dev, viapm->smbus);
446         }
447
448         if ((error = bus_release_resource(dev, SYS_RES_IOPORT,
449                                 viapm->iorid, viapm->iores)))
450                 return (error);
451
452 #if notyet
453         if ((error = bus_release_resource(dev, SYS_RES_IRQ,
454                                         viapm->irqrid, viapm->irqres))
455                 return (error);
456 #endif
457
458         return 0;
459 }
460
461 static int
462 viabb_callback(device_t dev, int index, caddr_t *data)
463 {
464         return 0;
465 }
466
467 static void
468 viabb_setscl(device_t dev, int ctrl)
469 {
470         struct viapm_softc *viapm = device_get_softc(dev);
471         u_char val;
472
473         val = VIAPM_INB(GPIO_VAL);
474
475         if (ctrl)
476                 val |= VIAPM_SCL;
477         else
478                 val &= ~VIAPM_SCL;
479
480         VIAPM_OUTB(GPIO_VAL, val);
481
482         return;
483 }
484
485 static void
486 viabb_setsda(device_t dev, int data)
487 {
488         struct viapm_softc *viapm = device_get_softc(dev);
489         u_char val;
490
491         val = VIAPM_INB(GPIO_VAL);
492
493         if (data)
494                 val |= VIAPM_SDA;
495         else
496                 val &= ~VIAPM_SDA;
497
498         VIAPM_OUTB(GPIO_VAL, val);
499
500         return;
501 }
502         
503 static int
504 viabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
505 {
506         /* reset bus */
507         viabb_setsda(dev, 1);
508         viabb_setscl(dev, 1);
509
510         return (IIC_ENOADDR);
511 }
512
513 #if 0
514 static int
515 viabb_getscl(device_t dev)
516 {
517         struct viapm_softc *viapm = device_get_softc(dev);
518
519         return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SCL) != 0);
520 }
521 #endif
522
523 static int
524 viabb_getsda(device_t dev)
525 {
526         struct viapm_softc *viapm = device_get_softc(dev);
527
528         return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SDA) != 0);
529 }
530
531 static void
532 viabb_setlines(device_t dev, int ctrl, int data)
533 {
534         viabb_setscl(dev, ctrl);
535         viabb_setsda(dev, data);
536
537         return;
538 }
539
540 static int
541 viapm_abort(struct viapm_softc *viapm)
542 {
543         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL);
544         DELAY(10);
545
546         return (0);
547 }
548
549 static int
550 viapm_clear(struct viapm_softc *viapm)
551 {
552         VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID |
553                 SMBHST_ERROR | SMBHST_INTR);
554         DELAY(10);
555
556         return (0);
557 }
558
559 static int
560 viapm_busy(struct viapm_softc *viapm)
561 {
562         u_char sts;
563
564         sts = VIAPM_INB(SMBHST);
565
566         VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts));
567
568         return (sts & SMBHST_BUSY);
569 }
570
571 /*
572  * Poll the SMBus controller
573  */
574 static int
575 viapm_wait(struct viapm_softc *viapm)
576 {
577         int count = 10000;
578         u_char sts = 0;
579         int error;
580
581         /* wait for command to complete and SMBus controller is idle */
582         while(count--) {
583                 DELAY(10);
584                 sts = VIAPM_INB(SMBHST);
585
586                 /* check if the controller is processing a command */
587                 if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR))
588                         break;
589         }
590
591         VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts));
592
593         error = SMB_ENOERR;
594
595         if (!count)
596                 error |= SMB_ETIMEOUT;
597
598         if (sts & SMBHST_FAILED)
599                 error |= SMB_EABORT;
600
601         if (sts & SMBHST_COLLID)
602                 error |= SMB_ENOACK;
603
604         if (sts & SMBHST_ERROR)
605                 error |= SMB_EBUSERR;
606
607         if (error != SMB_ENOERR)
608                 viapm_abort(viapm);
609
610         viapm_clear(viapm);
611
612         return (error);
613 }
614
615 static int
616 viasmb_callback(device_t dev, int index, caddr_t *data)
617 {
618         int error = 0;
619
620         switch (index) {
621         case SMB_REQUEST_BUS:
622         case SMB_RELEASE_BUS:
623                 /* ok, bus allocation accepted */
624                 break;
625         default:
626                 error = EINVAL;
627         }
628
629         return (error);
630 }
631
632 static int
633 viasmb_quick(device_t dev, u_char slave, int how)
634 {
635         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
636         int error;
637
638         viapm_clear(viapm);
639         if (viapm_busy(viapm))
640                 return (EBUSY);
641
642         switch (how) {
643         case SMB_QWRITE:
644                 VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave));
645                 VIAPM_OUTB(SMBHADDR, slave & ~LSB);
646                 break;
647         case SMB_QREAD:
648                 VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave));
649                 VIAPM_OUTB(SMBHADDR, slave | LSB);
650                 break;
651         default:
652                 panic("%s: unknown QUICK command (%x)!", __func__, how);
653         }
654
655         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK);
656
657         error = viapm_wait(viapm);
658
659         return (error);
660 }
661
662 static int
663 viasmb_sendb(device_t dev, u_char slave, char byte)
664 {
665         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
666         int error;
667
668         viapm_clear(viapm);
669         if (viapm_busy(viapm))
670                 return (EBUSY);
671
672         VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
673         VIAPM_OUTB(SMBHCMD, byte);
674
675         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
676
677         error = viapm_wait(viapm);
678
679         VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
680
681         return (error);
682 }
683
684 static int
685 viasmb_recvb(device_t dev, u_char slave, char *byte)
686 {
687         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
688         int error;
689
690         viapm_clear(viapm);
691         if (viapm_busy(viapm))
692                 return (EBUSY);
693
694         VIAPM_OUTB(SMBHADDR, slave | LSB);
695
696         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
697
698         if ((error = viapm_wait(viapm)) == SMB_ENOERR)
699                 *byte = VIAPM_INB(SMBHDATA0);
700
701         VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
702
703         return (error);
704 }
705
706 static int
707 viasmb_writeb(device_t dev, u_char slave, char cmd, char byte)
708 {
709         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
710         int error;
711
712         viapm_clear(viapm);
713         if (viapm_busy(viapm))
714                 return (EBUSY);
715
716         VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
717         VIAPM_OUTB(SMBHCMD, cmd);
718         VIAPM_OUTB(SMBHDATA0, byte);
719
720         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
721
722         error = viapm_wait(viapm);
723
724         VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
725
726         return (error);
727 }
728
729 static int
730 viasmb_readb(device_t dev, u_char slave, char cmd, char *byte)
731 {
732         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
733         int error;
734
735         viapm_clear(viapm);
736         if (viapm_busy(viapm))
737                 return (EBUSY);
738
739         VIAPM_OUTB(SMBHADDR, slave | LSB);
740         VIAPM_OUTB(SMBHCMD, cmd);
741
742         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
743
744         if ((error = viapm_wait(viapm)) == SMB_ENOERR)
745                 *byte = VIAPM_INB(SMBHDATA0);
746
747         VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
748
749         return (error);
750 }
751
752 static int
753 viasmb_writew(device_t dev, u_char slave, char cmd, short word)
754 {
755         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
756         int error;
757
758         viapm_clear(viapm);
759         if (viapm_busy(viapm))
760                 return (EBUSY);
761
762         VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
763         VIAPM_OUTB(SMBHCMD, cmd);
764         VIAPM_OUTB(SMBHDATA0, word & 0x00ff);
765         VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8);
766
767         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
768
769         error = viapm_wait(viapm);
770
771         VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
772
773         return (error);
774 }
775
776 static int
777 viasmb_readw(device_t dev, u_char slave, char cmd, short *word)
778 {
779         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
780         int error;
781         u_char high, low;
782
783         viapm_clear(viapm);
784         if (viapm_busy(viapm))
785                 return (EBUSY);
786
787         VIAPM_OUTB(SMBHADDR, slave | LSB);
788         VIAPM_OUTB(SMBHCMD, cmd);
789
790         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
791
792         if ((error = viapm_wait(viapm)) == SMB_ENOERR) {
793                 low = VIAPM_INB(SMBHDATA0);
794                 high = VIAPM_INB(SMBHDATA1);
795
796                 *word = ((high & 0xff) << 8) | (low & 0xff);
797         }
798
799         VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
800
801         return (error);
802 }
803
804 static int
805 viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
806 {
807         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
808         u_char remain, len, i;
809         int error = SMB_ENOERR;
810
811         viapm_clear(viapm);
812         if (viapm_busy(viapm))
813                 return (EBUSY);
814
815         remain = count;
816         while (remain) {
817                 len = min(remain, 32);
818
819                 VIAPM_OUTB(SMBHADDR, slave & ~LSB);
820                 VIAPM_OUTB(SMBHCMD, cmd);
821                 VIAPM_OUTB(SMBHDATA0, len);
822                 i = VIAPM_INB(SMBHCTRL);
823
824                 /* fill the 32-byte internal buffer */
825                 for (i=0; i<len; i++) {
826                         VIAPM_OUTB(SMBHBLOCK, buf[count-remain+i]);
827                         DELAY(2);
828                 }
829                 VIAPM_OUTB(SMBHCMD, cmd);
830                 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
831
832                 if ((error = viapm_wait(viapm)) != SMB_ENOERR)
833                         goto error;
834
835                 remain -= len;
836         }
837
838 error:
839         VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
840
841         return (error);
842
843 }
844
845 static int
846 viasmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
847 {
848         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
849         u_char remain, len, i;
850         int error = SMB_ENOERR;
851
852         viapm_clear(viapm);
853         if (viapm_busy(viapm))
854                 return (EBUSY);
855
856         remain = count;
857         while (remain) {
858                 VIAPM_OUTB(SMBHADDR, slave | LSB);
859                 VIAPM_OUTB(SMBHCMD, cmd);
860                 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
861
862                 if ((error = viapm_wait(viapm)) != SMB_ENOERR)
863                         goto error;
864
865                 len = VIAPM_INB(SMBHDATA0);
866                 i = VIAPM_INB(SMBHCTRL);                /* reset counter */
867
868                 len = min(len, remain);
869
870                 /* read the 32-byte internal buffer */
871                 for (i=0; i<len; i++) {
872                         buf[count-remain+i] = VIAPM_INB(SMBHBLOCK);
873                         DELAY(2);
874                 }
875
876                 remain -= len;
877         }
878 error:
879         VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
880
881         return (error);
882 }
883
884 static device_method_t viapm_methods[] = {
885         /* device interface */
886         DEVMETHOD(device_probe,         viapm_586b_probe),
887         DEVMETHOD(device_attach,        viapm_586b_attach),
888         DEVMETHOD(device_detach,        viapm_586b_detach),
889
890         /* iicbb interface */
891         DEVMETHOD(iicbb_callback,       viabb_callback),
892         DEVMETHOD(iicbb_setlines,       viabb_setlines),
893         DEVMETHOD(iicbb_getdataline,    viabb_getsda),
894         DEVMETHOD(iicbb_reset,          viabb_reset),
895
896         { 0, 0 }
897 };
898
899 static driver_t viapm_driver = {
900         "viapm",
901         viapm_methods,
902         sizeof(struct viapm_softc),
903 };
904
905 static device_method_t viapropm_methods[] = {
906         /* device interface */
907         DEVMETHOD(device_probe,         viapm_pro_probe),
908         DEVMETHOD(device_attach,        viapm_pro_attach),
909         DEVMETHOD(device_detach,        viapm_pro_detach),
910
911         /* smbus interface */
912         DEVMETHOD(smbus_callback,       viasmb_callback),
913         DEVMETHOD(smbus_quick,          viasmb_quick),
914         DEVMETHOD(smbus_sendb,          viasmb_sendb),
915         DEVMETHOD(smbus_recvb,          viasmb_recvb),
916         DEVMETHOD(smbus_writeb,         viasmb_writeb),
917         DEVMETHOD(smbus_readb,          viasmb_readb),
918         DEVMETHOD(smbus_writew,         viasmb_writew),
919         DEVMETHOD(smbus_readw,          viasmb_readw),
920         DEVMETHOD(smbus_bwrite,         viasmb_bwrite),
921         DEVMETHOD(smbus_bread,          viasmb_bread),
922         
923         { 0, 0 }
924 };
925
926 static driver_t viapropm_driver = {
927         "viapropm",
928         viapropm_methods,
929         sizeof(struct viapm_softc),
930 };
931
932 DECLARE_DUMMY_MODULE(viapm);
933 DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0);
934 DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0);
935
936 MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
937 MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
938 MODULE_VERSION(viapm, 1);