viapcib.c revision 1.10 1 /* $NetBSD: viapcib.c,v 1.10 2008/05/05 11:49:40 xtraeme Exp $ */
2 /* $FreeBSD: src/sys/pci/viapm.c,v 1.10 2005/05/29 04:42:29 nyan Exp $ */
3
4 /*-
5 * Copyright (c) 2005, 2006 Jared D. McNeill <jmcneill (at) invisible.ca>
6 * All rights reserved.
7 *
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.
18 *
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.
30 */
31 /*-
32 * Copyright (c) 2001 Alcove - Nicolas Souchu
33 * All rights reserved.
34 *
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.
43 *
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.
55 */
56
57 #include <sys/cdefs.h>
58 __KERNEL_RCSID(0, "$NetBSD: viapcib.c,v 1.10 2008/05/05 11:49:40 xtraeme Exp $");
59
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>
67
68 #include <dev/pci/pcireg.h>
69 #include <dev/pci/pcivar.h>
70 #include <dev/pci/pcidevs.h>
71
72 #include <dev/i2c/i2cvar.h>
73
74 #include <i386/pci/viapcibreg.h>
75
76 /*#define VIAPCIB_DEBUG*/
77
78 #ifdef VIAPCIB_DEBUG
79 #define DPRINTF(x) printf x
80 #else
81 #define DPRINTF(x)
82 #endif
83
84 struct viapcib_softc {
85 bus_space_tag_t sc_iot;
86 bus_space_handle_t sc_ioh;
87 struct i2c_controller sc_i2c;
88
89 int sc_revision;
90
91 struct simplelock sc_lock;
92 };
93
94 static int viapcib_match(device_t, cfdata_t, void *);
95 static void viapcib_attach(device_t, device_t, void *);
96
97 static int viapcib_clear(struct viapcib_softc *);
98 static int viapcib_busy(struct viapcib_softc *);
99
100 #define viapcib_smbus_read(sc, o) \
101 bus_space_read_1((sc)->sc_iot, (sc)->sc_ioh, (o))
102 #define viapcib_smbus_write(sc, o, v) \
103 bus_space_write_1((sc)->sc_iot, (sc)->sc_ioh, (o), (v))
104
105 #define VIAPCIB_SMBUS_TIMEOUT 10000
106
107 static int viapcib_acquire_bus(void *, int);
108 static void viapcib_release_bus(void *, int);
109 static int viapcib_exec(void *, i2c_op_t, i2c_addr_t, const void *,
110 size_t, void *, size_t, int);
111
112 /* SMBus operations */
113 static int viapcib_smbus_quick_write(void *, i2c_addr_t);
114 static int viapcib_smbus_quick_read(void *, i2c_addr_t);
115 static int viapcib_smbus_send_byte(void *, i2c_addr_t, uint8_t);
116 static int viapcib_smbus_receive_byte(void *, i2c_addr_t,
117 uint8_t *);
118 static int viapcib_smbus_read_byte(void *, i2c_addr_t, uint8_t,
119 int8_t *);
120 static int viapcib_smbus_write_byte(void *, i2c_addr_t, uint8_t,
121 int8_t);
122 static int viapcib_smbus_read_word(void *, i2c_addr_t, uint8_t,
123 int16_t *);
124 static int viapcib_smbus_write_word(void *, i2c_addr_t, uint8_t,
125 int16_t);
126 static int viapcib_smbus_block_write(void *, i2c_addr_t, uint8_t,
127 int, void *);
128 static int viapcib_smbus_block_read(void *, i2c_addr_t, uint8_t,
129 int, void *);
130 /* XXX Should be moved to smbus layer */
131 #define SMB_MAXBLOCKSIZE 32
132
133 /* from arch/i386/pci/pcib.c */
134 extern void pcibattach(device_t, device_t, void *);
135
136 CFATTACH_DECL_NEW(viapcib, sizeof(struct viapcib_softc),
137 viapcib_match, viapcib_attach, NULL, NULL);
138
139 static int
140 viapcib_match(device_t parent, cfdata_t match, void *opaque)
141 {
142 struct pci_attach_args *pa = opaque;
143
144 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH)
145 return 0;
146
147 switch (PCI_PRODUCT(pa->pa_id)) {
148 case PCI_PRODUCT_VIATECH_VT8235:
149 case PCI_PRODUCT_VIATECH_VT8237:
150 return 2; /* match above generic pcib(4) */
151 }
152
153 return 0;
154 }
155
156 static void
157 viapcib_attach(device_t parent, device_t self, void *opaque)
158 {
159 struct viapcib_softc *sc = device_private(self);
160 struct pci_attach_args *pa = opaque;
161 pcireg_t addr, val;
162
163 /* XXX Only the 8235 is supported for now */
164 sc->sc_iot = pa->pa_iot;
165 addr = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_BASE3);
166 addr &= 0xfff0;
167 if (bus_space_map(sc->sc_iot, addr, 8, 0, &sc->sc_ioh)) {
168 printf(": failed to map SMBus I/O space\n");
169 addr = 0;
170 goto core_pcib;
171 }
172
173 simple_lock_init(&sc->sc_lock);
174
175 val = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_HOST_CONFIG);
176 if ((val & 0x10000) == 0) {
177 printf(": SMBus is disabled\n");
178 addr = 0;
179 /* XXX We can enable the SMBus here by writing 1 to
180 * SMB_HOST_CONFIG, but do we want to?
181 */
182 goto core_pcib;
183 }
184
185 #ifdef VIAPCIB_DEBUG
186 switch (val & 0x0e) {
187 case 8:
188 printf(": interrupting at irq 9\n");
189 break;
190 case 0:
191 printf(": interrupting at SMI#\n");
192 break;
193 default:
194 printf(": interrupt misconfigured\n");
195 break;
196 }
197 #endif /* !VIAPCIB_DEBUG */
198
199 val = pci_conf_read(pa->pa_pc, pa->pa_tag, SMB_REVISION);
200 sc->sc_revision = val >> 16;
201
202 core_pcib:
203 pcibattach(parent, self, opaque);
204
205 if (addr != 0) {
206 struct i2cbus_attach_args iba;
207 uint8_t b;
208
209 printf("%s: SMBus found at 0x%x (revision 0x%x)\n",
210 device_xname(self), addr, sc->sc_revision);
211
212 /* Disable slave function */
213 b = viapcib_smbus_read(sc, SMBSLVCNT);
214 viapcib_smbus_write(sc, SMBSLVCNT, b & ~1);
215
216 memset(&sc->sc_i2c, 0, sizeof(sc->sc_i2c));
217 #ifdef I2C_TYPE_SMBUS
218 iba.iba_type = I2C_TYPE_SMBUS;
219 #endif
220 iba.iba_tag = &sc->sc_i2c;
221 iba.iba_tag->ic_cookie = (void *)sc;
222 iba.iba_tag->ic_acquire_bus = viapcib_acquire_bus;
223 iba.iba_tag->ic_release_bus = viapcib_release_bus;
224 iba.iba_tag->ic_exec = viapcib_exec;
225
226 config_found_ia(self, "i2cbus", &iba, iicbus_print);
227 }
228 }
229
230 static int
231 viapcib_wait(struct viapcib_softc *sc)
232 {
233 int rv, timeout;
234 uint8_t val;
235
236 timeout = VIAPCIB_SMBUS_TIMEOUT;
237 rv = 0;
238
239 while (timeout--) {
240 val = viapcib_smbus_read(sc, SMBHSTSTS);
241 if (!(val & SMBHSTSTS_BUSY) && (val & SMBHSTSTS_INTR))
242 break;
243 DELAY(10);
244 }
245
246 if (timeout == 0)
247 rv = EBUSY;
248
249 if ((val & SMBHSTSTS_FAILED) || (val & SMBHSTSTS_COLLISION) ||
250 (val & SMBHSTSTS_ERROR))
251 rv = EIO;
252
253 viapcib_clear(sc);
254
255 return rv;
256 }
257
258 static int
259 viapcib_clear(struct viapcib_softc *sc)
260 {
261 viapcib_smbus_write(sc, SMBHSTSTS,
262 (SMBHSTSTS_FAILED | SMBHSTSTS_COLLISION | SMBHSTSTS_ERROR |
263 SMBHSTSTS_INTR));
264 DELAY(10);
265
266 return 0;
267 }
268
269 static int
270 viapcib_busy(struct viapcib_softc *sc)
271 {
272 uint8_t val;
273
274 val = viapcib_smbus_read(sc, SMBHSTSTS);
275
276 return (val & SMBHSTSTS_BUSY);
277 }
278
279 static int
280 viapcib_acquire_bus(void *opaque, int flags)
281 {
282 struct viapcib_softc *sc;
283
284 DPRINTF(("viapcib_i2c_acquire_bus(%p, 0x%x)\n", opaque, flags));
285
286 sc = (struct viapcib_softc *)opaque;
287
288 simple_lock(&sc->sc_lock);
289
290 return 0;
291 }
292
293 static void
294 viapcib_release_bus(void *opaque, int flags)
295 {
296 struct viapcib_softc *sc;
297
298 DPRINTF(("viapcib_i2c_release_bus(%p, 0x%x)\n", opaque, flags));
299
300 sc = (struct viapcib_softc *)opaque;
301
302 simple_unlock(&sc->sc_lock);
303
304 return;
305 }
306
307 static int
308 viapcib_exec(void *opaque, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
309 size_t cmdlen, void *vbuf, size_t buflen, int flags)
310 {
311 struct viapcib_softc *sc;
312 uint8_t cmd;
313 int rv = -1;
314
315 DPRINTF(("viapcib_exec(%p, 0x%x, 0x%x, %p, %d, %p, %d, 0x%x)\n",
316 opaque, op, addr, vcmd, cmdlen, vbuf, buflen, flags));
317
318 sc = (struct viapcib_softc *)opaque;
319
320 if (op != I2C_OP_READ_WITH_STOP &&
321 op != I2C_OP_WRITE_WITH_STOP)
322 return -1;
323
324 if (cmdlen > 0)
325 cmd = *(uint8_t *)(__UNCONST(vcmd)); /* XXX */
326
327 switch (cmdlen) {
328 case 0:
329 switch (buflen) {
330 case 0:
331 /* SMBus quick read/write */
332 if (I2C_OP_READ_P(op))
333 rv = viapcib_smbus_quick_read(sc, addr);
334 else
335 rv = viapcib_smbus_quick_write(sc, addr);
336
337 return rv;
338 case 1:
339 /* SMBus send/receive byte */
340 if (I2C_OP_READ_P(op))
341 rv = viapcib_smbus_send_byte(sc, addr,
342 *(uint8_t *)vbuf);
343 else
344 rv = viapcib_smbus_receive_byte(sc, addr,
345 (uint8_t *)vbuf);
346 return rv;
347 default:
348 return -1;
349 }
350 case 1:
351 switch (buflen) {
352 case 0:
353 return -1;
354 case 1:
355 /* SMBus read/write byte */
356 if (I2C_OP_READ_P(op))
357 rv = viapcib_smbus_read_byte(sc, addr,
358 cmd, (uint8_t *)vbuf);
359 else
360 rv = viapcib_smbus_write_byte(sc, addr,
361 cmd, *(uint8_t *)vbuf);
362 return rv;
363 case 2:
364 /* SMBus read/write word */
365 if (I2C_OP_READ_P(op))
366 rv = viapcib_smbus_read_word(sc, addr,
367 cmd, (uint16_t *)vbuf);
368 else
369 rv = viapcib_smbus_write_word(sc, addr,
370 cmd, *(uint16_t *)vbuf);
371 return rv;
372 default:
373 /* SMBus read/write block */
374 if (I2C_OP_READ_P(op))
375 rv = viapcib_smbus_block_read(sc, addr,
376 cmd, buflen, vbuf);
377 else
378 rv = viapcib_smbus_block_write(sc, addr,
379 cmd, buflen, vbuf);
380 return rv;
381 }
382 }
383
384 return -1; /* XXX ??? */
385 }
386
387 static int
388 viapcib_smbus_quick_write(void *opaque, i2c_addr_t slave)
389 {
390 struct viapcib_softc *sc;
391
392 sc = (struct viapcib_softc *)opaque;
393
394 DPRINTF(("viapcib_smbus_quick_write(%p, 0x%x)\n", opaque, slave));
395
396 viapcib_clear(sc);
397 if (viapcib_busy(sc))
398 return EBUSY;
399
400 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
401 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK);
402 if (viapcib_wait(sc))
403 return EBUSY;
404 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START);
405
406 return viapcib_wait(sc);
407 }
408
409 static int
410 viapcib_smbus_quick_read(void *opaque, i2c_addr_t slave)
411 {
412 struct viapcib_softc *sc;
413
414 sc = (struct viapcib_softc *)opaque;
415
416 DPRINTF(("viapcib_smbus_quick_read(%p, 0x%x)\n", opaque, slave));
417
418 viapcib_clear(sc);
419 if (viapcib_busy(sc))
420 return EBUSY;
421
422 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
423 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK);
424 if (viapcib_wait(sc))
425 return EBUSY;
426 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START);
427
428 return viapcib_wait(sc);
429 }
430
431 static int
432 viapcib_smbus_send_byte(void *opaque, i2c_addr_t slave, uint8_t byte)
433 {
434 struct viapcib_softc *sc;
435
436 sc = (struct viapcib_softc *)opaque;
437
438 DPRINTF(("viapcib_smbus_send_byte(%p, 0x%x, 0x%x)\n", opaque,
439 slave, byte));
440
441 viapcib_clear(sc);
442 if (viapcib_busy(sc))
443 return EBUSY;
444
445 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
446 viapcib_smbus_write(sc, SMBHSTCMD, byte);
447 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV);
448 if (viapcib_wait(sc))
449 return EBUSY;
450 viapcib_smbus_write(sc, SMBHSTCNT,
451 SMBHSTCNT_START | SMBHSTCNT_SENDRECV);
452
453 return viapcib_wait(sc);
454 }
455
456 static int
457 viapcib_smbus_receive_byte(void *opaque, i2c_addr_t slave, uint8_t *pbyte)
458 {
459 struct viapcib_softc *sc;
460 int rv;
461
462 sc = (struct viapcib_softc *)opaque;
463
464 DPRINTF(("viapcib_smbus_receive_byte(%p, 0x%x, %p)\n", opaque,
465 slave, pbyte));
466
467 viapcib_clear(sc);
468 if (viapcib_busy(sc))
469 return EBUSY;
470
471 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
472 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV);
473 if (viapcib_wait(sc))
474 return EBUSY;
475 viapcib_smbus_write(sc, SMBHSTCNT,
476 SMBHSTCNT_START | SMBHSTCNT_SENDRECV);
477
478 rv = viapcib_wait(sc);
479 if (rv == 0)
480 *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0);
481
482 return rv;
483 }
484
485 static int
486 viapcib_smbus_write_byte(void *opaque, i2c_addr_t slave, uint8_t cmd,
487 int8_t byte)
488 {
489 struct viapcib_softc *sc;
490
491 sc = (struct viapcib_softc *)opaque;
492
493 DPRINTF(("viapcib_smbus_write_byte(%p, 0x%x, 0x%x, 0x%x)\n", opaque,
494 slave, cmd, byte));
495
496 viapcib_clear(sc);
497 if (viapcib_busy(sc))
498 return EBUSY;
499
500 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
501 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
502 viapcib_smbus_write(sc, SMBHSTDAT0, byte);
503 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE);
504 if (viapcib_wait(sc))
505 return EBUSY;
506 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE);
507
508 return viapcib_wait(sc);
509 }
510
511 static int
512 viapcib_smbus_read_byte(void *opaque, i2c_addr_t slave, uint8_t cmd,
513 int8_t *pbyte)
514 {
515 struct viapcib_softc *sc;
516 int rv;
517
518 sc = (struct viapcib_softc *)opaque;
519
520 DPRINTF(("viapcib_smbus_read_byte(%p, 0x%x, 0x%x, %p)\n", opaque,
521 slave, cmd, pbyte));
522
523 viapcib_clear(sc);
524 if (viapcib_busy(sc))
525 return EBUSY;
526
527 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
528 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
529 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE);
530 if (viapcib_wait(sc))
531 return EBUSY;
532 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE);
533 rv = viapcib_wait(sc);
534 if (rv == 0)
535 *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0);
536
537 return rv;
538 }
539
540 static int
541 viapcib_smbus_write_word(void *opaque, i2c_addr_t slave, uint8_t cmd,
542 int16_t word)
543 {
544 struct viapcib_softc *sc;
545
546 sc = (struct viapcib_softc *)opaque;
547
548 DPRINTF(("viapcib_smbus_write_word(%p, 0x%x, 0x%x, 0x%x)\n", opaque,
549 slave, cmd, word));
550
551 viapcib_clear(sc);
552 if (viapcib_busy(sc))
553 return EBUSY;
554
555 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
556 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
557 viapcib_smbus_write(sc, SMBHSTDAT0, word & 0x00ff);
558 viapcib_smbus_write(sc, SMBHSTDAT1, (word & 0xff00) >> 8);
559 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD);
560 if (viapcib_wait(sc))
561 return EBUSY;
562 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD);
563
564 return viapcib_wait(sc);
565 }
566
567 static int
568 viapcib_smbus_read_word(void *opaque, i2c_addr_t slave, uint8_t cmd,
569 int16_t *pword)
570 {
571 struct viapcib_softc *sc;
572 int rv;
573 int8_t high, low;
574
575 sc = (struct viapcib_softc *)opaque;
576
577 DPRINTF(("viapcib_smbus_read_word(%p, 0x%x, 0x%x, %p)\n", opaque,
578 slave, cmd, pword));
579
580 viapcib_clear(sc);
581 if (viapcib_busy(sc))
582 return EBUSY;
583
584 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
585 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
586 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD);
587 if (viapcib_wait(sc))
588 return EBUSY;
589 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD);
590
591 rv = viapcib_wait(sc);
592 if (rv == 0) {
593 low = viapcib_smbus_read(sc, SMBHSTDAT0);
594 high = viapcib_smbus_read(sc, SMBHSTDAT1);
595 *pword = ((high & 0xff) << 8) | (low & 0xff);
596 }
597
598 return rv;
599 }
600
601 static int
602 viapcib_smbus_block_write(void *opaque, i2c_addr_t slave, uint8_t cmd,
603 int cnt, void *data)
604 {
605 struct viapcib_softc *sc;
606 int8_t *buf;
607 int remain, len, i;
608 int rv;
609
610 sc = (struct viapcib_softc *)opaque;
611 buf = (int8_t *)data;
612 rv = 0;
613
614 DPRINTF(("viapcib_smbus_block_write(%p, 0x%x, 0x%x, %d, %p)\n",
615 opaque, slave, cmd, cnt, data));
616
617 viapcib_clear(sc);
618 if (viapcib_busy(sc))
619 return EBUSY;
620
621 remain = cnt;
622 while (remain) {
623 len = min(remain, SMB_MAXBLOCKSIZE);
624
625 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
626 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
627 viapcib_smbus_write(sc, SMBHSTDAT0, len);
628 i = viapcib_smbus_read(sc, SMBHSTCNT);
629 /* XXX FreeBSD does this, but it looks wrong */
630 for (i = 0; i < len; i++) {
631 viapcib_smbus_write(sc, SMBBLKDAT,
632 buf[cnt - remain + i]);
633 }
634 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK);
635 if (viapcib_wait(sc))
636 return EBUSY;
637 viapcib_smbus_write(sc, SMBHSTCNT,
638 SMBHSTCNT_START | SMBHSTCNT_BLOCK);
639 if (viapcib_wait(sc))
640 return EBUSY;
641
642 remain -= len;
643 }
644
645 return rv;
646 }
647
648 static int
649 viapcib_smbus_block_read(void *opaque, i2c_addr_t slave, uint8_t cmd,
650 int cnt, void *data)
651 {
652 struct viapcib_softc *sc;
653 int8_t *buf;
654 int remain, len, i;
655 int rv;
656
657 sc = (struct viapcib_softc *)opaque;
658 buf = (int8_t *)data;
659 rv = 0;
660
661 DPRINTF(("viapcib_smbus_block_read(%p, 0x%x, 0x%x, %d, %p)\n",
662 opaque, slave, cmd, cnt, data));
663
664 viapcib_clear(sc);
665 if (viapcib_busy(sc))
666 return EBUSY;
667
668 remain = cnt;
669 while (remain) {
670 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
671 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
672 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK);
673 if (viapcib_wait(sc))
674 return EBUSY;
675 viapcib_smbus_write(sc, SMBHSTCNT,
676 SMBHSTCNT_START | SMBHSTCNT_BLOCK);
677 if (viapcib_wait(sc))
678 return EBUSY;
679
680 len = viapcib_smbus_read(sc, SMBHSTDAT0);
681 i = viapcib_smbus_read(sc, SMBHSTCNT);
682
683 len = min(len, remain);
684
685 /* FreeBSD does this too... */
686 for (i = 0; i < len; i++) {
687 buf[cnt - remain + i] =
688 viapcib_smbus_read(sc, SMBBLKDAT);
689 }
690
691 remain -= len;
692 }
693
694 return rv;
695 }
696