Sync usage with man page.
[netbsd-mini2440.git] / sys / arch / i386 / pci / viapcib.c
blob9f7d8f15fb36bd2ea91c2c4f8ec13e2f19209dec
1 /* $NetBSD: viapcib.c,v 1.11 2008/07/20 16:59:53 martin Exp $ */
2 /* $FreeBSD: src/sys/pci/viapm.c,v 1.10 2005/05/29 04:42:29 nyan Exp $ */
4 /*-
5 * Copyright (c) 2005, 2006 Jared D. McNeill <jmcneill@invisible.ca>
6 * All rights reserved.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions, and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
24 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * SUCH DAMAGE.
31 /*-
32 * Copyright (c) 2001 Alcove - Nicolas Souchu
33 * All rights reserved.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
37 * are met:
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
45 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
46 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
47 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
48 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
49 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
50 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
51 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
52 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
53 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
54 * SUCH DAMAGE.
57 #include <sys/cdefs.h>
58 __KERNEL_RCSID(0, "$NetBSD: viapcib.c,v 1.11 2008/07/20 16:59:53 martin Exp $");
60 #include <sys/types.h>
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/device.h>
64 #include <sys/proc.h>
65 #include <sys/simplelock.h>
66 #include <sys/bus.h>
68 #include <dev/pci/pcireg.h>
69 #include <dev/pci/pcivar.h>
70 #include <dev/pci/pcidevs.h>
72 #include <dev/i2c/i2cvar.h>
74 #include <i386/pci/viapcibreg.h>
75 #include <x86/pci/pcibvar.h>
77 /*#define VIAPCIB_DEBUG*/
79 #ifdef VIAPCIB_DEBUG
80 #define DPRINTF(x) printf x
81 #else
82 #define DPRINTF(x)
83 #endif
85 struct viapcib_softc {
86 /* we call pcibattach(), which assumes softc starts like this: */
87 struct pcib_softc sc_pcib;
89 bus_space_tag_t sc_iot;
90 bus_space_handle_t sc_ioh;
91 struct i2c_controller sc_i2c;
93 int sc_revision;
95 struct simplelock sc_lock;
98 static int viapcib_match(device_t, cfdata_t, void *);
99 static void viapcib_attach(device_t, device_t, void *);
101 static int viapcib_clear(struct viapcib_softc *);
102 static int viapcib_busy(struct viapcib_softc *);
104 #define viapcib_smbus_read(sc, o) \
105 bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (o))
106 #define viapcib_smbus_write(sc, o, v) \
107 bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (o), (v))
109 #define VIAPCIB_SMBUS_TIMEOUT 10000
111 static int viapcib_acquire_bus(void *, int);
112 static void viapcib_release_bus(void *, int);
113 static int viapcib_exec(void *, i2c_op_t, i2c_addr_t, const void *,
114 size_t, void *, size_t, int);
116 /* SMBus operations */
117 static int viapcib_smbus_quick_write(void *, i2c_addr_t);
118 static int viapcib_smbus_quick_read(void *, i2c_addr_t);
119 static int viapcib_smbus_send_byte(void *, i2c_addr_t, uint8_t);
120 static int viapcib_smbus_receive_byte(void *, i2c_addr_t,
121 uint8_t *);
122 static int viapcib_smbus_read_byte(void *, i2c_addr_t, uint8_t,
123 int8_t *);
124 static int viapcib_smbus_write_byte(void *, i2c_addr_t, uint8_t,
125 int8_t);
126 static int viapcib_smbus_read_word(void *, i2c_addr_t, uint8_t,
127 int16_t *);
128 static int viapcib_smbus_write_word(void *, i2c_addr_t, uint8_t,
129 int16_t);
130 static int viapcib_smbus_block_write(void *, i2c_addr_t, uint8_t,
131 int, void *);
132 static int viapcib_smbus_block_read(void *, i2c_addr_t, uint8_t,
133 int, void *);
134 /* XXX Should be moved to smbus layer */
135 #define SMB_MAXBLOCKSIZE 32
137 CFATTACH_DECL_NEW(viapcib, sizeof(struct viapcib_softc),
138 viapcib_match, viapcib_attach, NULL, NULL);
140 static int
141 viapcib_match(device_t parent, cfdata_t match, void *opaque)
143 struct pci_attach_args *pa = opaque;
145 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH)
146 return 0;
148 switch (PCI_PRODUCT(pa->pa_id)) {
149 case PCI_PRODUCT_VIATECH_VT8235:
150 case PCI_PRODUCT_VIATECH_VT8237:
151 case PCI_PRODUCT_VIATECH_VT8237A_ISA:
152 return 2; /* match above generic pcib(4) */
155 return 0;
158 static void
159 viapcib_attach(device_t parent, device_t self, void *opaque)
161 struct viapcib_softc *sc = device_private(self);
162 struct pci_attach_args *pa = opaque;
163 pcireg_t addr, val;
165 /* XXX Only the 8235 is supported for now */
166 sc->sc_iot = pa->pa_iot;
167 addr = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_BASE3);
168 addr &= 0xfff0;
169 if (bus_space_map(sc->sc_iot, addr, 8, 0, &sc->sc_ioh)) {
170 printf(": failed to map SMBus I/O space\n");
171 addr = 0;
172 goto core_pcib;
175 simple_lock_init(&sc->sc_lock);
177 val = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_HOST_CONFIG);
178 if ((val & 0x10000) == 0) {
179 printf(": SMBus is disabled\n");
180 addr = 0;
181 /* XXX We can enable the SMBus here by writing 1 to
182 * SMB_HOST_CONFIG, but do we want to?
184 goto core_pcib;
187 #ifdef VIAPCIB_DEBUG
188 switch (val & 0x0e) {
189 case 8:
190 printf(": interrupting at irq 9\n");
191 break;
192 case 0:
193 printf(": interrupting at SMI#\n");
194 break;
195 default:
196 printf(": interrupt misconfigured\n");
197 break;
199 #endif /* !VIAPCIB_DEBUG */
201 val = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_REVISION);
202 sc->sc_revision = val >> 16;
204 core_pcib:
205 pcibattach(parent, self, opaque);
207 if (addr != 0) {
208 struct i2cbus_attach_args iba;
209 uint8_t b;
211 printf("%s: SMBus found at 0x%x (revision 0x%x)\n",
212 device_xname(self), addr, sc->sc_revision);
214 /* Disable slave function */
215 b = viapcib_smbus_read(sc, SMBSLVCNT);
216 viapcib_smbus_write(sc, SMBSLVCNT, b & ~1);
218 memset(&sc->sc_i2c, 0, sizeof(sc->sc_i2c));
219 #ifdef I2C_TYPE_SMBUS
220 iba.iba_type = I2C_TYPE_SMBUS;
221 #endif
222 iba.iba_tag = &sc->sc_i2c;
223 iba.iba_tag->ic_cookie = (void *)sc;
224 iba.iba_tag->ic_acquire_bus = viapcib_acquire_bus;
225 iba.iba_tag->ic_release_bus = viapcib_release_bus;
226 iba.iba_tag->ic_exec = viapcib_exec;
228 config_found_ia(self, "i2cbus", &iba, iicbus_print);
232 static int
233 viapcib_wait(struct viapcib_softc *sc)
235 int rv, timeout;
236 uint8_t val;
238 timeout = VIAPCIB_SMBUS_TIMEOUT;
239 rv = 0;
241 while (timeout--) {
242 val = viapcib_smbus_read(sc, SMBHSTSTS);
243 if (!(val & SMBHSTSTS_BUSY) && (val & SMBHSTSTS_INTR))
244 break;
245 DELAY(10);
248 if (timeout == 0)
249 rv = EBUSY;
251 if ((val & SMBHSTSTS_FAILED) || (val & SMBHSTSTS_COLLISION) ||
252 (val & SMBHSTSTS_ERROR))
253 rv = EIO;
255 viapcib_clear(sc);
257 return rv;
260 static int
261 viapcib_clear(struct viapcib_softc *sc)
263 viapcib_smbus_write(sc, SMBHSTSTS,
264 (SMBHSTSTS_FAILED | SMBHSTSTS_COLLISION | SMBHSTSTS_ERROR |
265 SMBHSTSTS_INTR));
266 DELAY(10);
268 return 0;
271 static int
272 viapcib_busy(struct viapcib_softc *sc)
274 uint8_t val;
276 val = viapcib_smbus_read(sc, SMBHSTSTS);
278 return (val & SMBHSTSTS_BUSY);
281 static int
282 viapcib_acquire_bus(void *opaque, int flags)
284 struct viapcib_softc *sc;
286 DPRINTF(("viapcib_i2c_acquire_bus(%p, 0x%x)\n", opaque, flags));
288 sc = (struct viapcib_softc *)opaque;
290 simple_lock(&sc->sc_lock);
292 return 0;
295 static void
296 viapcib_release_bus(void *opaque, int flags)
298 struct viapcib_softc *sc;
300 DPRINTF(("viapcib_i2c_release_bus(%p, 0x%x)\n", opaque, flags));
302 sc = (struct viapcib_softc *)opaque;
304 simple_unlock(&sc->sc_lock);
306 return;
309 static int
310 viapcib_exec(void *opaque, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
311 size_t cmdlen, void *vbuf, size_t buflen, int flags)
313 struct viapcib_softc *sc;
314 uint8_t cmd;
315 int rv = -1;
317 DPRINTF(("viapcib_exec(%p, 0x%x, 0x%x, %p, %d, %p, %d, 0x%x)\n",
318 opaque, op, addr, vcmd, cmdlen, vbuf, buflen, flags));
320 sc = (struct viapcib_softc *)opaque;
322 if (op != I2C_OP_READ_WITH_STOP &&
323 op != I2C_OP_WRITE_WITH_STOP)
324 return -1;
326 if (cmdlen > 0)
327 cmd = *(uint8_t *)(__UNCONST(vcmd)); /* XXX */
329 switch (cmdlen) {
330 case 0:
331 switch (buflen) {
332 case 0:
333 /* SMBus quick read/write */
334 if (I2C_OP_READ_P(op))
335 rv = viapcib_smbus_quick_read(sc, addr);
336 else
337 rv = viapcib_smbus_quick_write(sc, addr);
339 return rv;
340 case 1:
341 /* SMBus send/receive byte */
342 if (I2C_OP_READ_P(op))
343 rv = viapcib_smbus_send_byte(sc, addr,
344 *(uint8_t *)vbuf);
345 else
346 rv = viapcib_smbus_receive_byte(sc, addr,
347 (uint8_t *)vbuf);
348 return rv;
349 default:
350 return -1;
352 case 1:
353 switch (buflen) {
354 case 0:
355 return -1;
356 case 1:
357 /* SMBus read/write byte */
358 if (I2C_OP_READ_P(op))
359 rv = viapcib_smbus_read_byte(sc, addr,
360 cmd, (uint8_t *)vbuf);
361 else
362 rv = viapcib_smbus_write_byte(sc, addr,
363 cmd, *(uint8_t *)vbuf);
364 return rv;
365 case 2:
366 /* SMBus read/write word */
367 if (I2C_OP_READ_P(op))
368 rv = viapcib_smbus_read_word(sc, addr,
369 cmd, (uint16_t *)vbuf);
370 else
371 rv = viapcib_smbus_write_word(sc, addr,
372 cmd, *(uint16_t *)vbuf);
373 return rv;
374 default:
375 /* SMBus read/write block */
376 if (I2C_OP_READ_P(op))
377 rv = viapcib_smbus_block_read(sc, addr,
378 cmd, buflen, vbuf);
379 else
380 rv = viapcib_smbus_block_write(sc, addr,
381 cmd, buflen, vbuf);
382 return rv;
386 return -1; /* XXX ??? */
389 static int
390 viapcib_smbus_quick_write(void *opaque, i2c_addr_t slave)
392 struct viapcib_softc *sc;
394 sc = (struct viapcib_softc *)opaque;
396 DPRINTF(("viapcib_smbus_quick_write(%p, 0x%x)\n", opaque, slave));
398 viapcib_clear(sc);
399 if (viapcib_busy(sc))
400 return EBUSY;
402 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
403 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK);
404 if (viapcib_wait(sc))
405 return EBUSY;
406 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START);
408 return viapcib_wait(sc);
411 static int
412 viapcib_smbus_quick_read(void *opaque, i2c_addr_t slave)
414 struct viapcib_softc *sc;
416 sc = (struct viapcib_softc *)opaque;
418 DPRINTF(("viapcib_smbus_quick_read(%p, 0x%x)\n", opaque, slave));
420 viapcib_clear(sc);
421 if (viapcib_busy(sc))
422 return EBUSY;
424 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
425 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK);
426 if (viapcib_wait(sc))
427 return EBUSY;
428 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START);
430 return viapcib_wait(sc);
433 static int
434 viapcib_smbus_send_byte(void *opaque, i2c_addr_t slave, uint8_t byte)
436 struct viapcib_softc *sc;
438 sc = (struct viapcib_softc *)opaque;
440 DPRINTF(("viapcib_smbus_send_byte(%p, 0x%x, 0x%x)\n", opaque,
441 slave, byte));
443 viapcib_clear(sc);
444 if (viapcib_busy(sc))
445 return EBUSY;
447 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
448 viapcib_smbus_write(sc, SMBHSTCMD, byte);
449 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV);
450 if (viapcib_wait(sc))
451 return EBUSY;
452 viapcib_smbus_write(sc, SMBHSTCNT,
453 SMBHSTCNT_START | SMBHSTCNT_SENDRECV);
455 return viapcib_wait(sc);
458 static int
459 viapcib_smbus_receive_byte(void *opaque, i2c_addr_t slave, uint8_t *pbyte)
461 struct viapcib_softc *sc;
462 int rv;
464 sc = (struct viapcib_softc *)opaque;
466 DPRINTF(("viapcib_smbus_receive_byte(%p, 0x%x, %p)\n", opaque,
467 slave, pbyte));
469 viapcib_clear(sc);
470 if (viapcib_busy(sc))
471 return EBUSY;
473 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
474 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV);
475 if (viapcib_wait(sc))
476 return EBUSY;
477 viapcib_smbus_write(sc, SMBHSTCNT,
478 SMBHSTCNT_START | SMBHSTCNT_SENDRECV);
480 rv = viapcib_wait(sc);
481 if (rv == 0)
482 *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0);
484 return rv;
487 static int
488 viapcib_smbus_write_byte(void *opaque, i2c_addr_t slave, uint8_t cmd,
489 int8_t byte)
491 struct viapcib_softc *sc;
493 sc = (struct viapcib_softc *)opaque;
495 DPRINTF(("viapcib_smbus_write_byte(%p, 0x%x, 0x%x, 0x%x)\n", opaque,
496 slave, cmd, byte));
498 viapcib_clear(sc);
499 if (viapcib_busy(sc))
500 return EBUSY;
502 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
503 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
504 viapcib_smbus_write(sc, SMBHSTDAT0, byte);
505 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE);
506 if (viapcib_wait(sc))
507 return EBUSY;
508 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE);
510 return viapcib_wait(sc);
513 static int
514 viapcib_smbus_read_byte(void *opaque, i2c_addr_t slave, uint8_t cmd,
515 int8_t *pbyte)
517 struct viapcib_softc *sc;
518 int rv;
520 sc = (struct viapcib_softc *)opaque;
522 DPRINTF(("viapcib_smbus_read_byte(%p, 0x%x, 0x%x, %p)\n", opaque,
523 slave, cmd, pbyte));
525 viapcib_clear(sc);
526 if (viapcib_busy(sc))
527 return EBUSY;
529 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
530 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
531 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE);
532 if (viapcib_wait(sc))
533 return EBUSY;
534 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE);
535 rv = viapcib_wait(sc);
536 if (rv == 0)
537 *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0);
539 return rv;
542 static int
543 viapcib_smbus_write_word(void *opaque, i2c_addr_t slave, uint8_t cmd,
544 int16_t word)
546 struct viapcib_softc *sc;
548 sc = (struct viapcib_softc *)opaque;
550 DPRINTF(("viapcib_smbus_write_word(%p, 0x%x, 0x%x, 0x%x)\n", opaque,
551 slave, cmd, word));
553 viapcib_clear(sc);
554 if (viapcib_busy(sc))
555 return EBUSY;
557 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
558 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
559 viapcib_smbus_write(sc, SMBHSTDAT0, word & 0x00ff);
560 viapcib_smbus_write(sc, SMBHSTDAT1, (word & 0xff00) >> 8);
561 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD);
562 if (viapcib_wait(sc))
563 return EBUSY;
564 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD);
566 return viapcib_wait(sc);
569 static int
570 viapcib_smbus_read_word(void *opaque, i2c_addr_t slave, uint8_t cmd,
571 int16_t *pword)
573 struct viapcib_softc *sc;
574 int rv;
575 int8_t high, low;
577 sc = (struct viapcib_softc *)opaque;
579 DPRINTF(("viapcib_smbus_read_word(%p, 0x%x, 0x%x, %p)\n", opaque,
580 slave, cmd, pword));
582 viapcib_clear(sc);
583 if (viapcib_busy(sc))
584 return EBUSY;
586 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
587 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
588 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD);
589 if (viapcib_wait(sc))
590 return EBUSY;
591 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD);
593 rv = viapcib_wait(sc);
594 if (rv == 0) {
595 low = viapcib_smbus_read(sc, SMBHSTDAT0);
596 high = viapcib_smbus_read(sc, SMBHSTDAT1);
597 *pword = ((high & 0xff) << 8) | (low & 0xff);
600 return rv;
603 static int
604 viapcib_smbus_block_write(void *opaque, i2c_addr_t slave, uint8_t cmd,
605 int cnt, void *data)
607 struct viapcib_softc *sc;
608 int8_t *buf;
609 int remain, len, i;
610 int rv;
612 sc = (struct viapcib_softc *)opaque;
613 buf = (int8_t *)data;
614 rv = 0;
616 DPRINTF(("viapcib_smbus_block_write(%p, 0x%x, 0x%x, %d, %p)\n",
617 opaque, slave, cmd, cnt, data));
619 viapcib_clear(sc);
620 if (viapcib_busy(sc))
621 return EBUSY;
623 remain = cnt;
624 while (remain) {
625 len = min(remain, SMB_MAXBLOCKSIZE);
627 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
628 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
629 viapcib_smbus_write(sc, SMBHSTDAT0, len);
630 i = viapcib_smbus_read(sc, SMBHSTCNT);
631 /* XXX FreeBSD does this, but it looks wrong */
632 for (i = 0; i < len; i++) {
633 viapcib_smbus_write(sc, SMBBLKDAT,
634 buf[cnt - remain + i]);
636 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK);
637 if (viapcib_wait(sc))
638 return EBUSY;
639 viapcib_smbus_write(sc, SMBHSTCNT,
640 SMBHSTCNT_START | SMBHSTCNT_BLOCK);
641 if (viapcib_wait(sc))
642 return EBUSY;
644 remain -= len;
647 return rv;
650 static int
651 viapcib_smbus_block_read(void *opaque, i2c_addr_t slave, uint8_t cmd,
652 int cnt, void *data)
654 struct viapcib_softc *sc;
655 int8_t *buf;
656 int remain, len, i;
657 int rv;
659 sc = (struct viapcib_softc *)opaque;
660 buf = (int8_t *)data;
661 rv = 0;
663 DPRINTF(("viapcib_smbus_block_read(%p, 0x%x, 0x%x, %d, %p)\n",
664 opaque, slave, cmd, cnt, data));
666 viapcib_clear(sc);
667 if (viapcib_busy(sc))
668 return EBUSY;
670 remain = cnt;
671 while (remain) {
672 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
673 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
674 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK);
675 if (viapcib_wait(sc))
676 return EBUSY;
677 viapcib_smbus_write(sc, SMBHSTCNT,
678 SMBHSTCNT_START | SMBHSTCNT_BLOCK);
679 if (viapcib_wait(sc))
680 return EBUSY;
682 len = viapcib_smbus_read(sc, SMBHSTDAT0);
683 i = viapcib_smbus_read(sc, SMBHSTCNT);
685 len = min(len, remain);
687 /* FreeBSD does this too... */
688 for (i = 0; i < len; i++) {
689 buf[cnt - remain + i] =
690 viapcib_smbus_read(sc, SMBBLKDAT);
693 remain -= len;
696 return rv;