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 $ */
5 * Copyright (c) 2005, 2006 Jared D. McNeill <jmcneill@invisible.ca>
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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
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
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
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>
65 #include <sys/simplelock.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*/
80 #define DPRINTF(x) printf x
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
;
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
,
122 static int viapcib_smbus_read_byte(void *, i2c_addr_t
, uint8_t,
124 static int viapcib_smbus_write_byte(void *, i2c_addr_t
, uint8_t,
126 static int viapcib_smbus_read_word(void *, i2c_addr_t
, uint8_t,
128 static int viapcib_smbus_write_word(void *, i2c_addr_t
, uint8_t,
130 static int viapcib_smbus_block_write(void *, i2c_addr_t
, uint8_t,
132 static int viapcib_smbus_block_read(void *, i2c_addr_t
, uint8_t,
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
);
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
)
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) */
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
;
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
);
169 if (bus_space_map(sc
->sc_iot
, addr
, 8, 0, &sc
->sc_ioh
)) {
170 printf(": failed to map SMBus I/O space\n");
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");
181 /* XXX We can enable the SMBus here by writing 1 to
182 * SMB_HOST_CONFIG, but do we want to?
188 switch (val
& 0x0e) {
190 printf(": interrupting at irq 9\n");
193 printf(": interrupting at SMI#\n");
196 printf(": interrupt misconfigured\n");
199 #endif /* !VIAPCIB_DEBUG */
201 val
= pci_conf_read(pa
->pa_pc
, pa
->pa_tag
, SMB_REVISION
);
202 sc
->sc_revision
= val
>> 16;
205 pcibattach(parent
, self
, opaque
);
208 struct i2cbus_attach_args iba
;
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
;
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
);
233 viapcib_wait(struct viapcib_softc
*sc
)
238 timeout
= VIAPCIB_SMBUS_TIMEOUT
;
242 val
= viapcib_smbus_read(sc
, SMBHSTSTS
);
243 if (!(val
& SMBHSTSTS_BUSY
) && (val
& SMBHSTSTS_INTR
))
251 if ((val
& SMBHSTSTS_FAILED
) || (val
& SMBHSTSTS_COLLISION
) ||
252 (val
& SMBHSTSTS_ERROR
))
261 viapcib_clear(struct viapcib_softc
*sc
)
263 viapcib_smbus_write(sc
, SMBHSTSTS
,
264 (SMBHSTSTS_FAILED
| SMBHSTSTS_COLLISION
| SMBHSTSTS_ERROR
|
272 viapcib_busy(struct viapcib_softc
*sc
)
276 val
= viapcib_smbus_read(sc
, SMBHSTSTS
);
278 return (val
& SMBHSTSTS_BUSY
);
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
);
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
);
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
;
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
)
327 cmd
= *(uint8_t *)(__UNCONST(vcmd
)); /* XXX */
333 /* SMBus quick read/write */
334 if (I2C_OP_READ_P(op
))
335 rv
= viapcib_smbus_quick_read(sc
, addr
);
337 rv
= viapcib_smbus_quick_write(sc
, addr
);
341 /* SMBus send/receive byte */
342 if (I2C_OP_READ_P(op
))
343 rv
= viapcib_smbus_send_byte(sc
, addr
,
346 rv
= viapcib_smbus_receive_byte(sc
, addr
,
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
);
362 rv
= viapcib_smbus_write_byte(sc
, addr
,
363 cmd
, *(uint8_t *)vbuf
);
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
);
371 rv
= viapcib_smbus_write_word(sc
, addr
,
372 cmd
, *(uint16_t *)vbuf
);
375 /* SMBus read/write block */
376 if (I2C_OP_READ_P(op
))
377 rv
= viapcib_smbus_block_read(sc
, addr
,
380 rv
= viapcib_smbus_block_write(sc
, addr
,
386 return -1; /* XXX ??? */
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
));
399 if (viapcib_busy(sc
))
402 viapcib_smbus_write(sc
, SMBHSTADD
, (slave
& 0x7f) << 1);
403 viapcib_smbus_write(sc
, SMBHSTCNT
, SMBHSTCNT_QUICK
);
404 if (viapcib_wait(sc
))
406 viapcib_smbus_write(sc
, SMBHSTCNT
, SMBHSTCNT_QUICK
| SMBHSTCNT_START
);
408 return viapcib_wait(sc
);
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
));
421 if (viapcib_busy(sc
))
424 viapcib_smbus_write(sc
, SMBHSTADD
, ((slave
& 0x7f) << 1) | 1);
425 viapcib_smbus_write(sc
, SMBHSTCNT
, SMBHSTCNT_QUICK
);
426 if (viapcib_wait(sc
))
428 viapcib_smbus_write(sc
, SMBHSTCNT
, SMBHSTCNT_QUICK
| SMBHSTCNT_START
);
430 return viapcib_wait(sc
);
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
,
444 if (viapcib_busy(sc
))
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
))
452 viapcib_smbus_write(sc
, SMBHSTCNT
,
453 SMBHSTCNT_START
| SMBHSTCNT_SENDRECV
);
455 return viapcib_wait(sc
);
459 viapcib_smbus_receive_byte(void *opaque
, i2c_addr_t slave
, uint8_t *pbyte
)
461 struct viapcib_softc
*sc
;
464 sc
= (struct viapcib_softc
*)opaque
;
466 DPRINTF(("viapcib_smbus_receive_byte(%p, 0x%x, %p)\n", opaque
,
470 if (viapcib_busy(sc
))
473 viapcib_smbus_write(sc
, SMBHSTADD
, ((slave
& 0x7f) << 1) | 1);
474 viapcib_smbus_write(sc
, SMBHSTCNT
, SMBHSTCNT_SENDRECV
);
475 if (viapcib_wait(sc
))
477 viapcib_smbus_write(sc
, SMBHSTCNT
,
478 SMBHSTCNT_START
| SMBHSTCNT_SENDRECV
);
480 rv
= viapcib_wait(sc
);
482 *pbyte
= viapcib_smbus_read(sc
, SMBHSTDAT0
);
488 viapcib_smbus_write_byte(void *opaque
, i2c_addr_t slave
, uint8_t cmd
,
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
,
499 if (viapcib_busy(sc
))
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
))
508 viapcib_smbus_write(sc
, SMBHSTCNT
, SMBHSTCNT_START
| SMBHSTCNT_BYTE
);
510 return viapcib_wait(sc
);
514 viapcib_smbus_read_byte(void *opaque
, i2c_addr_t slave
, uint8_t cmd
,
517 struct viapcib_softc
*sc
;
520 sc
= (struct viapcib_softc
*)opaque
;
522 DPRINTF(("viapcib_smbus_read_byte(%p, 0x%x, 0x%x, %p)\n", opaque
,
526 if (viapcib_busy(sc
))
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
))
534 viapcib_smbus_write(sc
, SMBHSTCNT
, SMBHSTCNT_START
| SMBHSTCNT_BYTE
);
535 rv
= viapcib_wait(sc
);
537 *pbyte
= viapcib_smbus_read(sc
, SMBHSTDAT0
);
543 viapcib_smbus_write_word(void *opaque
, i2c_addr_t slave
, uint8_t cmd
,
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
,
554 if (viapcib_busy(sc
))
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
))
564 viapcib_smbus_write(sc
, SMBHSTCNT
, SMBHSTCNT_START
| SMBHSTCNT_WORD
);
566 return viapcib_wait(sc
);
570 viapcib_smbus_read_word(void *opaque
, i2c_addr_t slave
, uint8_t cmd
,
573 struct viapcib_softc
*sc
;
577 sc
= (struct viapcib_softc
*)opaque
;
579 DPRINTF(("viapcib_smbus_read_word(%p, 0x%x, 0x%x, %p)\n", opaque
,
583 if (viapcib_busy(sc
))
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
))
591 viapcib_smbus_write(sc
, SMBHSTCNT
, SMBHSTCNT_START
| SMBHSTCNT_WORD
);
593 rv
= viapcib_wait(sc
);
595 low
= viapcib_smbus_read(sc
, SMBHSTDAT0
);
596 high
= viapcib_smbus_read(sc
, SMBHSTDAT1
);
597 *pword
= ((high
& 0xff) << 8) | (low
& 0xff);
604 viapcib_smbus_block_write(void *opaque
, i2c_addr_t slave
, uint8_t cmd
,
607 struct viapcib_softc
*sc
;
612 sc
= (struct viapcib_softc
*)opaque
;
613 buf
= (int8_t *)data
;
616 DPRINTF(("viapcib_smbus_block_write(%p, 0x%x, 0x%x, %d, %p)\n",
617 opaque
, slave
, cmd
, cnt
, data
));
620 if (viapcib_busy(sc
))
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
))
639 viapcib_smbus_write(sc
, SMBHSTCNT
,
640 SMBHSTCNT_START
| SMBHSTCNT_BLOCK
);
641 if (viapcib_wait(sc
))
651 viapcib_smbus_block_read(void *opaque
, i2c_addr_t slave
, uint8_t cmd
,
654 struct viapcib_softc
*sc
;
659 sc
= (struct viapcib_softc
*)opaque
;
660 buf
= (int8_t *)data
;
663 DPRINTF(("viapcib_smbus_block_read(%p, 0x%x, 0x%x, %d, %p)\n",
664 opaque
, slave
, cmd
, cnt
, data
));
667 if (viapcib_busy(sc
))
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
))
677 viapcib_smbus_write(sc
, SMBHSTCNT
,
678 SMBHSTCNT_START
| SMBHSTCNT_BLOCK
);
679 if (viapcib_wait(sc
))
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
);