kernel tree reorganization stage 1: Major cvs repository work (not logged as
[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.3 2003/08/07 21:17:07 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
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)!", __FUNCTION__,
650                         how);
651         }
652
653         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK);
654
655         error = viapm_wait(viapm);
656
657         return (error);
658 }
659
660 static int
661 viasmb_sendb(device_t dev, u_char slave, char byte)
662 {
663         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
664         int error;
665
666         viapm_clear(viapm);
667         if (viapm_busy(viapm))
668                 return (EBUSY);
669
670         VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
671         VIAPM_OUTB(SMBHCMD, byte);
672
673         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
674
675         error = viapm_wait(viapm);
676
677         VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error));
678
679         return (error);
680 }
681
682 static int
683 viasmb_recvb(device_t dev, u_char slave, char *byte)
684 {
685         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
686         int error;
687
688         viapm_clear(viapm);
689         if (viapm_busy(viapm))
690                 return (EBUSY);
691
692         VIAPM_OUTB(SMBHADDR, slave | LSB);
693
694         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV);
695
696         if ((error = viapm_wait(viapm)) == SMB_ENOERR)
697                 *byte = VIAPM_INB(SMBHDATA0);
698
699         VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error));
700
701         return (error);
702 }
703
704 static int
705 viasmb_writeb(device_t dev, u_char slave, char cmd, char byte)
706 {
707         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
708         int error;
709
710         viapm_clear(viapm);
711         if (viapm_busy(viapm))
712                 return (EBUSY);
713
714         VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
715         VIAPM_OUTB(SMBHCMD, cmd);
716         VIAPM_OUTB(SMBHDATA0, byte);
717
718         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
719
720         error = viapm_wait(viapm);
721
722         VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error));
723
724         return (error);
725 }
726
727 static int
728 viasmb_readb(device_t dev, u_char slave, char cmd, char *byte)
729 {
730         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
731         int error;
732
733         viapm_clear(viapm);
734         if (viapm_busy(viapm))
735                 return (EBUSY);
736
737         VIAPM_OUTB(SMBHADDR, slave | LSB);
738         VIAPM_OUTB(SMBHCMD, cmd);
739
740         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE);
741
742         if ((error = viapm_wait(viapm)) == SMB_ENOERR)
743                 *byte = VIAPM_INB(SMBHDATA0);
744
745         VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error));
746
747         return (error);
748 }
749
750 static int
751 viasmb_writew(device_t dev, u_char slave, char cmd, short word)
752 {
753         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
754         int error;
755
756         viapm_clear(viapm);
757         if (viapm_busy(viapm))
758                 return (EBUSY);
759
760         VIAPM_OUTB(SMBHADDR, slave & ~ LSB);
761         VIAPM_OUTB(SMBHCMD, cmd);
762         VIAPM_OUTB(SMBHDATA0, word & 0x00ff);
763         VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8);
764
765         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
766
767         error = viapm_wait(viapm);
768
769         VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error));
770
771         return (error);
772 }
773
774 static int
775 viasmb_readw(device_t dev, u_char slave, char cmd, short *word)
776 {
777         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
778         int error;
779         u_char high, low;
780
781         viapm_clear(viapm);
782         if (viapm_busy(viapm))
783                 return (EBUSY);
784
785         VIAPM_OUTB(SMBHADDR, slave | LSB);
786         VIAPM_OUTB(SMBHCMD, cmd);
787
788         VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD);
789
790         if ((error = viapm_wait(viapm)) == SMB_ENOERR) {
791                 low = VIAPM_INB(SMBHDATA0);
792                 high = VIAPM_INB(SMBHDATA1);
793
794                 *word = ((high & 0xff) << 8) | (low & 0xff);
795         }
796
797         VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error));
798
799         return (error);
800 }
801
802 static int
803 viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
804 {
805         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
806         u_char remain, len, i;
807         int error = SMB_ENOERR;
808
809         viapm_clear(viapm);
810         if (viapm_busy(viapm))
811                 return (EBUSY);
812
813         remain = count;
814         while (remain) {
815                 len = min(remain, 32);
816
817                 VIAPM_OUTB(SMBHADDR, slave & ~LSB);
818                 VIAPM_OUTB(SMBHCMD, cmd);
819                 VIAPM_OUTB(SMBHDATA0, len);
820                 i = VIAPM_INB(SMBHCTRL);
821
822                 /* fill the 32-byte internal buffer */
823                 for (i=0; i<len; i++) {
824                         VIAPM_OUTB(SMBHBLOCK, buf[count-remain+i]);
825                         DELAY(2);
826                 }
827                 VIAPM_OUTB(SMBHCMD, cmd);
828                 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
829
830                 if ((error = viapm_wait(viapm)) != SMB_ENOERR)
831                         goto error;
832
833                 remain -= len;
834         }
835
836 error:
837         VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
838
839         return (error);
840
841 }
842
843 static int
844 viasmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
845 {
846         struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev);
847         u_char remain, len, i;
848         int error = SMB_ENOERR;
849
850         viapm_clear(viapm);
851         if (viapm_busy(viapm))
852                 return (EBUSY);
853
854         remain = count;
855         while (remain) {
856                 VIAPM_OUTB(SMBHADDR, slave | LSB);
857                 VIAPM_OUTB(SMBHCMD, cmd);
858                 VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK);
859
860                 if ((error = viapm_wait(viapm)) != SMB_ENOERR)
861                         goto error;
862
863                 len = VIAPM_INB(SMBHDATA0);
864                 i = VIAPM_INB(SMBHCTRL);                /* reset counter */
865
866                 len = min(len, remain);
867
868                 /* read the 32-byte internal buffer */
869                 for (i=0; i<len; i++) {
870                         buf[count-remain+i] = VIAPM_INB(SMBHBLOCK);
871                         DELAY(2);
872                 }
873
874                 remain -= len;
875         }
876 error:
877         VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error));
878
879         return (error);
880 }
881
882 static device_method_t viapm_methods[] = {
883         /* device interface */
884         DEVMETHOD(device_probe,         viapm_586b_probe),
885         DEVMETHOD(device_attach,        viapm_586b_attach),
886         DEVMETHOD(device_detach,        viapm_586b_detach),
887
888         /* iicbb interface */
889         DEVMETHOD(iicbb_callback,       viabb_callback),
890         DEVMETHOD(iicbb_setlines,       viabb_setlines),
891         DEVMETHOD(iicbb_getdataline,    viabb_getsda),
892         DEVMETHOD(iicbb_reset,          viabb_reset),
893
894         { 0, 0 }
895 };
896
897 static driver_t viapm_driver = {
898         "viapm",
899         viapm_methods,
900         sizeof(struct viapm_softc),
901 };
902
903 static device_method_t viapropm_methods[] = {
904         /* device interface */
905         DEVMETHOD(device_probe,         viapm_pro_probe),
906         DEVMETHOD(device_attach,        viapm_pro_attach),
907         DEVMETHOD(device_detach,        viapm_pro_detach),
908
909         /* smbus interface */
910         DEVMETHOD(smbus_callback,       viasmb_callback),
911         DEVMETHOD(smbus_quick,          viasmb_quick),
912         DEVMETHOD(smbus_sendb,          viasmb_sendb),
913         DEVMETHOD(smbus_recvb,          viasmb_recvb),
914         DEVMETHOD(smbus_writeb,         viasmb_writeb),
915         DEVMETHOD(smbus_readb,          viasmb_readb),
916         DEVMETHOD(smbus_writew,         viasmb_writew),
917         DEVMETHOD(smbus_readw,          viasmb_readw),
918         DEVMETHOD(smbus_bwrite,         viasmb_bwrite),
919         DEVMETHOD(smbus_bread,          viasmb_bread),
920         
921         { 0, 0 }
922 };
923
924 static driver_t viapropm_driver = {
925         "viapropm",
926         viapropm_methods,
927         sizeof(struct viapm_softc),
928 };
929
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);