viapcib.c revision 1.14 1 /* $NetBSD: viapcib.c,v 1.14 2011/07/05 07:08:17 mrg 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.14 2011/07/05 07:08:17 mrg 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 #ifdef I2C_TYPE_SMBUS
219 iba.iba_type = I2C_TYPE_SMBUS;
220 #endif
221 iba.iba_tag = &sc->sc_i2c;
222 iba.iba_tag->ic_cookie = (void *)sc;
223 iba.iba_tag->ic_acquire_bus = viapcib_acquire_bus;
224 iba.iba_tag->ic_release_bus = viapcib_release_bus;
225 iba.iba_tag->ic_exec = viapcib_exec;
226
227 config_found_ia(self, "i2cbus", &iba, iicbus_print);
228 }
229 }
230
231 static int
232 viapcib_wait(struct viapcib_softc *sc)
233 {
234 int rv, timeout;
235 uint8_t val = 0;
236
237 timeout = VIAPCIB_SMBUS_TIMEOUT;
238 rv = 0;
239
240 while (timeout--) {
241 val = viapcib_smbus_read(sc, SMBHSTSTS);
242 if (!(val & SMBHSTSTS_BUSY) && (val & SMBHSTSTS_INTR))
243 break;
244 DELAY(10);
245 }
246
247 if (timeout == 0)
248 rv = EBUSY;
249
250 if ((val & SMBHSTSTS_FAILED) || (val & SMBHSTSTS_COLLISION) ||
251 (val & SMBHSTSTS_ERROR))
252 rv = EIO;
253
254 viapcib_clear(sc);
255
256 return rv;
257 }
258
259 static int
260 viapcib_clear(struct viapcib_softc *sc)
261 {
262 viapcib_smbus_write(sc, SMBHSTSTS,
263 (SMBHSTSTS_FAILED | SMBHSTSTS_COLLISION | SMBHSTSTS_ERROR |
264 SMBHSTSTS_INTR));
265 DELAY(10);
266
267 return 0;
268 }
269
270 static int
271 viapcib_busy(struct viapcib_softc *sc)
272 {
273 uint8_t val;
274
275 val = viapcib_smbus_read(sc, SMBHSTSTS);
276
277 return (val & SMBHSTSTS_BUSY);
278 }
279
280 static int
281 viapcib_acquire_bus(void *opaque, int flags)
282 {
283 struct viapcib_softc *sc = (struct viapcib_softc *)opaque;
284
285 DPRINTF(("viapcib_i2c_acquire_bus(%p, 0x%x)\n", opaque, flags));
286 mutex_enter(&sc->sc_lock);
287
288 return 0;
289 }
290
291 static void
292 viapcib_release_bus(void *opaque, int flags)
293 {
294 struct viapcib_softc *sc = (struct viapcib_softc *)opaque;
295
296 mutex_exit(&sc->sc_lock);
297 DPRINTF(("viapcib_i2c_release_bus(%p, 0x%x)\n", opaque, flags));
298 }
299
300 static int
301 viapcib_exec(void *opaque, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
302 size_t cmdlen, void *vbuf, size_t buflen, int flags)
303 {
304 struct viapcib_softc *sc;
305 uint8_t cmd;
306 int rv = -1;
307
308 DPRINTF(("viapcib_exec(%p, 0x%x, 0x%x, %p, %d, %p, %d, 0x%x)\n",
309 opaque, op, addr, vcmd, cmdlen, vbuf, buflen, flags));
310
311 sc = (struct viapcib_softc *)opaque;
312
313 if (op != I2C_OP_READ_WITH_STOP &&
314 op != I2C_OP_WRITE_WITH_STOP)
315 return -1;
316
317 if (cmdlen > 0)
318 cmd = *(uint8_t *)(__UNCONST(vcmd)); /* XXX */
319
320 switch (cmdlen) {
321 case 0:
322 switch (buflen) {
323 case 0:
324 /* SMBus quick read/write */
325 if (I2C_OP_READ_P(op))
326 rv = viapcib_smbus_quick_read(sc, addr);
327 else
328 rv = viapcib_smbus_quick_write(sc, addr);
329
330 return rv;
331 case 1:
332 /* SMBus send/receive byte */
333 if (I2C_OP_READ_P(op))
334 rv = viapcib_smbus_send_byte(sc, addr,
335 *(uint8_t *)vbuf);
336 else
337 rv = viapcib_smbus_receive_byte(sc, addr,
338 (uint8_t *)vbuf);
339 return rv;
340 default:
341 return -1;
342 }
343 case 1:
344 switch (buflen) {
345 case 0:
346 return -1;
347 case 1:
348 /* SMBus read/write byte */
349 if (I2C_OP_READ_P(op))
350 rv = viapcib_smbus_read_byte(sc, addr,
351 cmd, (uint8_t *)vbuf);
352 else
353 rv = viapcib_smbus_write_byte(sc, addr,
354 cmd, *(uint8_t *)vbuf);
355 return rv;
356 case 2:
357 /* SMBus read/write word */
358 if (I2C_OP_READ_P(op))
359 rv = viapcib_smbus_read_word(sc, addr,
360 cmd, (uint16_t *)vbuf);
361 else
362 rv = viapcib_smbus_write_word(sc, addr,
363 cmd, *(uint16_t *)vbuf);
364 return rv;
365 default:
366 /* SMBus read/write block */
367 if (I2C_OP_READ_P(op))
368 rv = viapcib_smbus_block_read(sc, addr,
369 cmd, buflen, vbuf);
370 else
371 rv = viapcib_smbus_block_write(sc, addr,
372 cmd, buflen, vbuf);
373 return rv;
374 }
375 }
376
377 return -1; /* XXX ??? */
378 }
379
380 static int
381 viapcib_smbus_quick_write(void *opaque, i2c_addr_t slave)
382 {
383 struct viapcib_softc *sc;
384
385 sc = (struct viapcib_softc *)opaque;
386
387 DPRINTF(("viapcib_smbus_quick_write(%p, 0x%x)\n", opaque, slave));
388
389 viapcib_clear(sc);
390 if (viapcib_busy(sc))
391 return EBUSY;
392
393 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
394 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK);
395 if (viapcib_wait(sc))
396 return EBUSY;
397 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START);
398
399 return viapcib_wait(sc);
400 }
401
402 static int
403 viapcib_smbus_quick_read(void *opaque, i2c_addr_t slave)
404 {
405 struct viapcib_softc *sc;
406
407 sc = (struct viapcib_softc *)opaque;
408
409 DPRINTF(("viapcib_smbus_quick_read(%p, 0x%x)\n", opaque, slave));
410
411 viapcib_clear(sc);
412 if (viapcib_busy(sc))
413 return EBUSY;
414
415 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
416 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK);
417 if (viapcib_wait(sc))
418 return EBUSY;
419 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START);
420
421 return viapcib_wait(sc);
422 }
423
424 static int
425 viapcib_smbus_send_byte(void *opaque, i2c_addr_t slave, uint8_t byte)
426 {
427 struct viapcib_softc *sc;
428
429 sc = (struct viapcib_softc *)opaque;
430
431 DPRINTF(("viapcib_smbus_send_byte(%p, 0x%x, 0x%x)\n", opaque,
432 slave, byte));
433
434 viapcib_clear(sc);
435 if (viapcib_busy(sc))
436 return EBUSY;
437
438 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
439 viapcib_smbus_write(sc, SMBHSTCMD, byte);
440 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV);
441 if (viapcib_wait(sc))
442 return EBUSY;
443 viapcib_smbus_write(sc, SMBHSTCNT,
444 SMBHSTCNT_START | SMBHSTCNT_SENDRECV);
445
446 return viapcib_wait(sc);
447 }
448
449 static int
450 viapcib_smbus_receive_byte(void *opaque, i2c_addr_t slave, uint8_t *pbyte)
451 {
452 struct viapcib_softc *sc;
453 int rv;
454
455 sc = (struct viapcib_softc *)opaque;
456
457 DPRINTF(("viapcib_smbus_receive_byte(%p, 0x%x, %p)\n", opaque,
458 slave, pbyte));
459
460 viapcib_clear(sc);
461 if (viapcib_busy(sc))
462 return EBUSY;
463
464 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
465 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV);
466 if (viapcib_wait(sc))
467 return EBUSY;
468 viapcib_smbus_write(sc, SMBHSTCNT,
469 SMBHSTCNT_START | SMBHSTCNT_SENDRECV);
470
471 rv = viapcib_wait(sc);
472 if (rv == 0)
473 *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0);
474
475 return rv;
476 }
477
478 static int
479 viapcib_smbus_write_byte(void *opaque, i2c_addr_t slave, uint8_t cmd,
480 int8_t byte)
481 {
482 struct viapcib_softc *sc;
483
484 sc = (struct viapcib_softc *)opaque;
485
486 DPRINTF(("viapcib_smbus_write_byte(%p, 0x%x, 0x%x, 0x%x)\n", opaque,
487 slave, cmd, byte));
488
489 viapcib_clear(sc);
490 if (viapcib_busy(sc))
491 return EBUSY;
492
493 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
494 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
495 viapcib_smbus_write(sc, SMBHSTDAT0, byte);
496 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE);
497 if (viapcib_wait(sc))
498 return EBUSY;
499 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE);
500
501 return viapcib_wait(sc);
502 }
503
504 static int
505 viapcib_smbus_read_byte(void *opaque, i2c_addr_t slave, uint8_t cmd,
506 int8_t *pbyte)
507 {
508 struct viapcib_softc *sc;
509 int rv;
510
511 sc = (struct viapcib_softc *)opaque;
512
513 DPRINTF(("viapcib_smbus_read_byte(%p, 0x%x, 0x%x, %p)\n", opaque,
514 slave, cmd, pbyte));
515
516 viapcib_clear(sc);
517 if (viapcib_busy(sc))
518 return EBUSY;
519
520 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
521 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
522 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE);
523 if (viapcib_wait(sc))
524 return EBUSY;
525 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE);
526 rv = viapcib_wait(sc);
527 if (rv == 0)
528 *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0);
529
530 return rv;
531 }
532
533 static int
534 viapcib_smbus_write_word(void *opaque, i2c_addr_t slave, uint8_t cmd,
535 int16_t word)
536 {
537 struct viapcib_softc *sc;
538
539 sc = (struct viapcib_softc *)opaque;
540
541 DPRINTF(("viapcib_smbus_write_word(%p, 0x%x, 0x%x, 0x%x)\n", opaque,
542 slave, cmd, word));
543
544 viapcib_clear(sc);
545 if (viapcib_busy(sc))
546 return EBUSY;
547
548 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
549 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
550 viapcib_smbus_write(sc, SMBHSTDAT0, word & 0x00ff);
551 viapcib_smbus_write(sc, SMBHSTDAT1, (word & 0xff00) >> 8);
552 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD);
553 if (viapcib_wait(sc))
554 return EBUSY;
555 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD);
556
557 return viapcib_wait(sc);
558 }
559
560 static int
561 viapcib_smbus_read_word(void *opaque, i2c_addr_t slave, uint8_t cmd,
562 int16_t *pword)
563 {
564 struct viapcib_softc *sc;
565 int rv;
566 int8_t high, low;
567
568 sc = (struct viapcib_softc *)opaque;
569
570 DPRINTF(("viapcib_smbus_read_word(%p, 0x%x, 0x%x, %p)\n", opaque,
571 slave, cmd, pword));
572
573 viapcib_clear(sc);
574 if (viapcib_busy(sc))
575 return EBUSY;
576
577 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
578 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
579 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD);
580 if (viapcib_wait(sc))
581 return EBUSY;
582 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD);
583
584 rv = viapcib_wait(sc);
585 if (rv == 0) {
586 low = viapcib_smbus_read(sc, SMBHSTDAT0);
587 high = viapcib_smbus_read(sc, SMBHSTDAT1);
588 *pword = ((high & 0xff) << 8) | (low & 0xff);
589 }
590
591 return rv;
592 }
593
594 static int
595 viapcib_smbus_block_write(void *opaque, i2c_addr_t slave, uint8_t cmd,
596 int cnt, void *data)
597 {
598 struct viapcib_softc *sc;
599 int8_t *buf;
600 int remain, len, i;
601 int rv;
602
603 sc = (struct viapcib_softc *)opaque;
604 buf = (int8_t *)data;
605 rv = 0;
606
607 DPRINTF(("viapcib_smbus_block_write(%p, 0x%x, 0x%x, %d, %p)\n",
608 opaque, slave, cmd, cnt, data));
609
610 viapcib_clear(sc);
611 if (viapcib_busy(sc))
612 return EBUSY;
613
614 remain = cnt;
615 while (remain) {
616 len = min(remain, SMB_MAXBLOCKSIZE);
617
618 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
619 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
620 viapcib_smbus_write(sc, SMBHSTDAT0, len);
621 i = viapcib_smbus_read(sc, SMBHSTCNT);
622 /* XXX FreeBSD does this, but it looks wrong */
623 for (i = 0; i < len; i++) {
624 viapcib_smbus_write(sc, SMBBLKDAT,
625 buf[cnt - remain + i]);
626 }
627 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK);
628 if (viapcib_wait(sc))
629 return EBUSY;
630 viapcib_smbus_write(sc, SMBHSTCNT,
631 SMBHSTCNT_START | SMBHSTCNT_BLOCK);
632 if (viapcib_wait(sc))
633 return EBUSY;
634
635 remain -= len;
636 }
637
638 return rv;
639 }
640
641 static int
642 viapcib_smbus_block_read(void *opaque, i2c_addr_t slave, uint8_t cmd,
643 int cnt, void *data)
644 {
645 struct viapcib_softc *sc;
646 int8_t *buf;
647 int remain, len, i;
648 int rv;
649
650 sc = (struct viapcib_softc *)opaque;
651 buf = (int8_t *)data;
652 rv = 0;
653
654 DPRINTF(("viapcib_smbus_block_read(%p, 0x%x, 0x%x, %d, %p)\n",
655 opaque, slave, cmd, cnt, data));
656
657 viapcib_clear(sc);
658 if (viapcib_busy(sc))
659 return EBUSY;
660
661 remain = cnt;
662 while (remain) {
663 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
664 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
665 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK);
666 if (viapcib_wait(sc))
667 return EBUSY;
668 viapcib_smbus_write(sc, SMBHSTCNT,
669 SMBHSTCNT_START | SMBHSTCNT_BLOCK);
670 if (viapcib_wait(sc))
671 return EBUSY;
672
673 len = viapcib_smbus_read(sc, SMBHSTDAT0);
674 i = viapcib_smbus_read(sc, SMBHSTCNT);
675
676 len = min(len, remain);
677
678 /* FreeBSD does this too... */
679 for (i = 0; i < len; i++) {
680 buf[cnt - remain + i] =
681 viapcib_smbus_read(sc, SMBBLKDAT);
682 }
683
684 remain -= len;
685 }
686
687 return rv;
688 }
689