viapcib.c revision 1.11 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 $ */
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.11 2008/07/20 16:59:53 martin 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 #include <x86/pci/pcibvar.h>
76
77 /*#define VIAPCIB_DEBUG*/
78
79 #ifdef VIAPCIB_DEBUG
80 #define DPRINTF(x) printf x
81 #else
82 #define DPRINTF(x)
83 #endif
84
85 struct viapcib_softc {
86 /* we call pcibattach(), which assumes softc starts like this: */
87 struct pcib_softc sc_pcib;
88
89 bus_space_tag_t sc_iot;
90 bus_space_handle_t sc_ioh;
91 struct i2c_controller sc_i2c;
92
93 int sc_revision;
94
95 struct simplelock sc_lock;
96 };
97
98 static int viapcib_match(device_t, cfdata_t, void *);
99 static void viapcib_attach(device_t, device_t, void *);
100
101 static int viapcib_clear(struct viapcib_softc *);
102 static int viapcib_busy(struct viapcib_softc *);
103
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))
108
109 #define VIAPCIB_SMBUS_TIMEOUT 10000
110
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);
115
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
136
137 CFATTACH_DECL_NEW(viapcib, sizeof(struct viapcib_softc),
138 viapcib_match, viapcib_attach, NULL, NULL);
139
140 static int
141 viapcib_match(device_t parent, cfdata_t match, void *opaque)
142 {
143 struct pci_attach_args *pa = opaque;
144
145 if (PCI_VENDOR(pa->pa_id) != PCI_VENDOR_VIATECH)
146 return 0;
147
148 switch (PCI_PRODUCT(pa->pa_id)) {
149 case PCI_PRODUCT_VIATECH_VT8235:
150 case PCI_PRODUCT_VIATECH_VT8237:
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 simple_lock_init(&sc->sc_lock);
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;
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;
284
285 DPRINTF(("viapcib_i2c_acquire_bus(%p, 0x%x)\n", opaque, flags));
286
287 sc = (struct viapcib_softc *)opaque;
288
289 simple_lock(&sc->sc_lock);
290
291 return 0;
292 }
293
294 static void
295 viapcib_release_bus(void *opaque, int flags)
296 {
297 struct viapcib_softc *sc;
298
299 DPRINTF(("viapcib_i2c_release_bus(%p, 0x%x)\n", opaque, flags));
300
301 sc = (struct viapcib_softc *)opaque;
302
303 simple_unlock(&sc->sc_lock);
304
305 return;
306 }
307
308 static int
309 viapcib_exec(void *opaque, i2c_op_t op, i2c_addr_t addr, const void *vcmd,
310 size_t cmdlen, void *vbuf, size_t buflen, int flags)
311 {
312 struct viapcib_softc *sc;
313 uint8_t cmd;
314 int rv = -1;
315
316 DPRINTF(("viapcib_exec(%p, 0x%x, 0x%x, %p, %d, %p, %d, 0x%x)\n",
317 opaque, op, addr, vcmd, cmdlen, vbuf, buflen, flags));
318
319 sc = (struct viapcib_softc *)opaque;
320
321 if (op != I2C_OP_READ_WITH_STOP &&
322 op != I2C_OP_WRITE_WITH_STOP)
323 return -1;
324
325 if (cmdlen > 0)
326 cmd = *(uint8_t *)(__UNCONST(vcmd)); /* XXX */
327
328 switch (cmdlen) {
329 case 0:
330 switch (buflen) {
331 case 0:
332 /* SMBus quick read/write */
333 if (I2C_OP_READ_P(op))
334 rv = viapcib_smbus_quick_read(sc, addr);
335 else
336 rv = viapcib_smbus_quick_write(sc, addr);
337
338 return rv;
339 case 1:
340 /* SMBus send/receive byte */
341 if (I2C_OP_READ_P(op))
342 rv = viapcib_smbus_send_byte(sc, addr,
343 *(uint8_t *)vbuf);
344 else
345 rv = viapcib_smbus_receive_byte(sc, addr,
346 (uint8_t *)vbuf);
347 return rv;
348 default:
349 return -1;
350 }
351 case 1:
352 switch (buflen) {
353 case 0:
354 return -1;
355 case 1:
356 /* SMBus read/write byte */
357 if (I2C_OP_READ_P(op))
358 rv = viapcib_smbus_read_byte(sc, addr,
359 cmd, (uint8_t *)vbuf);
360 else
361 rv = viapcib_smbus_write_byte(sc, addr,
362 cmd, *(uint8_t *)vbuf);
363 return rv;
364 case 2:
365 /* SMBus read/write word */
366 if (I2C_OP_READ_P(op))
367 rv = viapcib_smbus_read_word(sc, addr,
368 cmd, (uint16_t *)vbuf);
369 else
370 rv = viapcib_smbus_write_word(sc, addr,
371 cmd, *(uint16_t *)vbuf);
372 return rv;
373 default:
374 /* SMBus read/write block */
375 if (I2C_OP_READ_P(op))
376 rv = viapcib_smbus_block_read(sc, addr,
377 cmd, buflen, vbuf);
378 else
379 rv = viapcib_smbus_block_write(sc, addr,
380 cmd, buflen, vbuf);
381 return rv;
382 }
383 }
384
385 return -1; /* XXX ??? */
386 }
387
388 static int
389 viapcib_smbus_quick_write(void *opaque, i2c_addr_t slave)
390 {
391 struct viapcib_softc *sc;
392
393 sc = (struct viapcib_softc *)opaque;
394
395 DPRINTF(("viapcib_smbus_quick_write(%p, 0x%x)\n", opaque, slave));
396
397 viapcib_clear(sc);
398 if (viapcib_busy(sc))
399 return EBUSY;
400
401 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
402 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK);
403 if (viapcib_wait(sc))
404 return EBUSY;
405 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START);
406
407 return viapcib_wait(sc);
408 }
409
410 static int
411 viapcib_smbus_quick_read(void *opaque, i2c_addr_t slave)
412 {
413 struct viapcib_softc *sc;
414
415 sc = (struct viapcib_softc *)opaque;
416
417 DPRINTF(("viapcib_smbus_quick_read(%p, 0x%x)\n", opaque, slave));
418
419 viapcib_clear(sc);
420 if (viapcib_busy(sc))
421 return EBUSY;
422
423 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
424 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK);
425 if (viapcib_wait(sc))
426 return EBUSY;
427 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_QUICK | SMBHSTCNT_START);
428
429 return viapcib_wait(sc);
430 }
431
432 static int
433 viapcib_smbus_send_byte(void *opaque, i2c_addr_t slave, uint8_t byte)
434 {
435 struct viapcib_softc *sc;
436
437 sc = (struct viapcib_softc *)opaque;
438
439 DPRINTF(("viapcib_smbus_send_byte(%p, 0x%x, 0x%x)\n", opaque,
440 slave, byte));
441
442 viapcib_clear(sc);
443 if (viapcib_busy(sc))
444 return EBUSY;
445
446 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
447 viapcib_smbus_write(sc, SMBHSTCMD, byte);
448 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV);
449 if (viapcib_wait(sc))
450 return EBUSY;
451 viapcib_smbus_write(sc, SMBHSTCNT,
452 SMBHSTCNT_START | SMBHSTCNT_SENDRECV);
453
454 return viapcib_wait(sc);
455 }
456
457 static int
458 viapcib_smbus_receive_byte(void *opaque, i2c_addr_t slave, uint8_t *pbyte)
459 {
460 struct viapcib_softc *sc;
461 int rv;
462
463 sc = (struct viapcib_softc *)opaque;
464
465 DPRINTF(("viapcib_smbus_receive_byte(%p, 0x%x, %p)\n", opaque,
466 slave, pbyte));
467
468 viapcib_clear(sc);
469 if (viapcib_busy(sc))
470 return EBUSY;
471
472 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
473 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_SENDRECV);
474 if (viapcib_wait(sc))
475 return EBUSY;
476 viapcib_smbus_write(sc, SMBHSTCNT,
477 SMBHSTCNT_START | SMBHSTCNT_SENDRECV);
478
479 rv = viapcib_wait(sc);
480 if (rv == 0)
481 *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0);
482
483 return rv;
484 }
485
486 static int
487 viapcib_smbus_write_byte(void *opaque, i2c_addr_t slave, uint8_t cmd,
488 int8_t byte)
489 {
490 struct viapcib_softc *sc;
491
492 sc = (struct viapcib_softc *)opaque;
493
494 DPRINTF(("viapcib_smbus_write_byte(%p, 0x%x, 0x%x, 0x%x)\n", opaque,
495 slave, cmd, byte));
496
497 viapcib_clear(sc);
498 if (viapcib_busy(sc))
499 return EBUSY;
500
501 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
502 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
503 viapcib_smbus_write(sc, SMBHSTDAT0, byte);
504 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE);
505 if (viapcib_wait(sc))
506 return EBUSY;
507 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE);
508
509 return viapcib_wait(sc);
510 }
511
512 static int
513 viapcib_smbus_read_byte(void *opaque, i2c_addr_t slave, uint8_t cmd,
514 int8_t *pbyte)
515 {
516 struct viapcib_softc *sc;
517 int rv;
518
519 sc = (struct viapcib_softc *)opaque;
520
521 DPRINTF(("viapcib_smbus_read_byte(%p, 0x%x, 0x%x, %p)\n", opaque,
522 slave, cmd, pbyte));
523
524 viapcib_clear(sc);
525 if (viapcib_busy(sc))
526 return EBUSY;
527
528 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
529 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
530 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BYTE);
531 if (viapcib_wait(sc))
532 return EBUSY;
533 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_BYTE);
534 rv = viapcib_wait(sc);
535 if (rv == 0)
536 *pbyte = viapcib_smbus_read(sc, SMBHSTDAT0);
537
538 return rv;
539 }
540
541 static int
542 viapcib_smbus_write_word(void *opaque, i2c_addr_t slave, uint8_t cmd,
543 int16_t word)
544 {
545 struct viapcib_softc *sc;
546
547 sc = (struct viapcib_softc *)opaque;
548
549 DPRINTF(("viapcib_smbus_write_word(%p, 0x%x, 0x%x, 0x%x)\n", opaque,
550 slave, cmd, word));
551
552 viapcib_clear(sc);
553 if (viapcib_busy(sc))
554 return EBUSY;
555
556 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
557 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
558 viapcib_smbus_write(sc, SMBHSTDAT0, word & 0x00ff);
559 viapcib_smbus_write(sc, SMBHSTDAT1, (word & 0xff00) >> 8);
560 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD);
561 if (viapcib_wait(sc))
562 return EBUSY;
563 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD);
564
565 return viapcib_wait(sc);
566 }
567
568 static int
569 viapcib_smbus_read_word(void *opaque, i2c_addr_t slave, uint8_t cmd,
570 int16_t *pword)
571 {
572 struct viapcib_softc *sc;
573 int rv;
574 int8_t high, low;
575
576 sc = (struct viapcib_softc *)opaque;
577
578 DPRINTF(("viapcib_smbus_read_word(%p, 0x%x, 0x%x, %p)\n", opaque,
579 slave, cmd, pword));
580
581 viapcib_clear(sc);
582 if (viapcib_busy(sc))
583 return EBUSY;
584
585 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
586 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
587 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_WORD);
588 if (viapcib_wait(sc))
589 return EBUSY;
590 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_START | SMBHSTCNT_WORD);
591
592 rv = viapcib_wait(sc);
593 if (rv == 0) {
594 low = viapcib_smbus_read(sc, SMBHSTDAT0);
595 high = viapcib_smbus_read(sc, SMBHSTDAT1);
596 *pword = ((high & 0xff) << 8) | (low & 0xff);
597 }
598
599 return rv;
600 }
601
602 static int
603 viapcib_smbus_block_write(void *opaque, i2c_addr_t slave, uint8_t cmd,
604 int cnt, void *data)
605 {
606 struct viapcib_softc *sc;
607 int8_t *buf;
608 int remain, len, i;
609 int rv;
610
611 sc = (struct viapcib_softc *)opaque;
612 buf = (int8_t *)data;
613 rv = 0;
614
615 DPRINTF(("viapcib_smbus_block_write(%p, 0x%x, 0x%x, %d, %p)\n",
616 opaque, slave, cmd, cnt, data));
617
618 viapcib_clear(sc);
619 if (viapcib_busy(sc))
620 return EBUSY;
621
622 remain = cnt;
623 while (remain) {
624 len = min(remain, SMB_MAXBLOCKSIZE);
625
626 viapcib_smbus_write(sc, SMBHSTADD, (slave & 0x7f) << 1);
627 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
628 viapcib_smbus_write(sc, SMBHSTDAT0, len);
629 i = viapcib_smbus_read(sc, SMBHSTCNT);
630 /* XXX FreeBSD does this, but it looks wrong */
631 for (i = 0; i < len; i++) {
632 viapcib_smbus_write(sc, SMBBLKDAT,
633 buf[cnt - remain + i]);
634 }
635 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK);
636 if (viapcib_wait(sc))
637 return EBUSY;
638 viapcib_smbus_write(sc, SMBHSTCNT,
639 SMBHSTCNT_START | SMBHSTCNT_BLOCK);
640 if (viapcib_wait(sc))
641 return EBUSY;
642
643 remain -= len;
644 }
645
646 return rv;
647 }
648
649 static int
650 viapcib_smbus_block_read(void *opaque, i2c_addr_t slave, uint8_t cmd,
651 int cnt, void *data)
652 {
653 struct viapcib_softc *sc;
654 int8_t *buf;
655 int remain, len, i;
656 int rv;
657
658 sc = (struct viapcib_softc *)opaque;
659 buf = (int8_t *)data;
660 rv = 0;
661
662 DPRINTF(("viapcib_smbus_block_read(%p, 0x%x, 0x%x, %d, %p)\n",
663 opaque, slave, cmd, cnt, data));
664
665 viapcib_clear(sc);
666 if (viapcib_busy(sc))
667 return EBUSY;
668
669 remain = cnt;
670 while (remain) {
671 viapcib_smbus_write(sc, SMBHSTADD, ((slave & 0x7f) << 1) | 1);
672 viapcib_smbus_write(sc, SMBHSTCMD, cmd);
673 viapcib_smbus_write(sc, SMBHSTCNT, SMBHSTCNT_BLOCK);
674 if (viapcib_wait(sc))
675 return EBUSY;
676 viapcib_smbus_write(sc, SMBHSTCNT,
677 SMBHSTCNT_START | SMBHSTCNT_BLOCK);
678 if (viapcib_wait(sc))
679 return EBUSY;
680
681 len = viapcib_smbus_read(sc, SMBHSTDAT0);
682 i = viapcib_smbus_read(sc, SMBHSTCNT);
683
684 len = min(len, remain);
685
686 /* FreeBSD does this too... */
687 for (i = 0; i < len; i++) {
688 buf[cnt - remain + i] =
689 viapcib_smbus_read(sc, SMBBLKDAT);
690 }
691
692 remain -= len;
693 }
694
695 return rv;
696 }
697