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