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