1 /* $NetBSD: i2c.c,v 1.22 2008/09/29 22:55:08 pgoyette Exp $ */
4 * Copyright (c) 2003 Wasabi Systems, Inc.
7 * Written by Jason R. Thorpe for Wasabi Systems, Inc.
9 * Redistribution and use in source and binary forms, with or without
10 * modification, are permitted provided that the following conditions
12 * 1. Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
17 * 3. All advertising materials mentioning features or use of this software
18 * must display the following acknowledgement:
19 * This product includes software developed for the NetBSD Project by
20 * Wasabi Systems, Inc.
21 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 * or promote products derived from this software without specific prior
25 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 * POSSIBILITY OF SUCH DAMAGE.
38 #include <sys/cdefs.h>
39 __KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.22 2008/09/29 22:55:08 pgoyette Exp $");
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/device.h>
44 #include <sys/event.h>
46 #include <sys/malloc.h>
47 #include <sys/kthread.h>
49 #include <sys/kernel.h>
51 #include <dev/i2c/i2cvar.h>
54 #include <opt_i2cbus.h>
61 static void iic_smbus_intr_thread(void *);
64 iicbus_print(void *aux
, const char *pnp
)
68 aprint_normal("iic at %s", pnp
);
74 iic_print(void *aux
, const char *pnp
)
76 struct i2c_attach_args
*ia
= aux
;
78 if (ia
->ia_addr
!= (i2c_addr_t
)-1)
79 aprint_normal(" addr 0x%x", ia
->ia_addr
);
85 iic_search(device_t parent
, cfdata_t cf
, const int *ldesc
, void *aux
)
87 struct iic_softc
*sc
= device_private(parent
);
88 struct i2c_attach_args ia
;
90 ia
.ia_tag
= sc
->sc_tag
;
91 ia
.ia_addr
= cf
->cf_loc
[IICCF_ADDR
];
92 ia
.ia_size
= cf
->cf_loc
[IICCF_SIZE
];
93 ia
.ia_type
= sc
->sc_type
;
95 if (config_match(parent
, cf
, &ia
) > 0)
96 config_attach(parent
, cf
, &ia
, iic_print
);
102 iic_match(device_t parent
, cfdata_t cf
, void *aux
)
109 iic_attach(device_t parent
, device_t self
, void *aux
)
111 struct iic_softc
*sc
= device_private(self
);
112 struct i2cbus_attach_args
*iba
= aux
;
116 aprint_naive(": I2C bus\n");
117 aprint_normal(": I2C bus\n");
119 sc
->sc_tag
= iba
->iba_tag
;
120 sc
->sc_type
= iba
->iba_type
;
122 ic
->ic_devname
= device_xname(self
);
124 LIST_INIT(&(sc
->sc_tag
->ic_list
));
125 LIST_INIT(&(sc
->sc_tag
->ic_proc_list
));
127 rv
= kthread_create(PRI_NONE
, 0, NULL
, iic_smbus_intr_thread
,
128 ic
, &ic
->ic_intr_thread
, "%s", ic
->ic_devname
);
130 aprint_error_dev(self
, "unable to create intr thread\n");
133 if (sc
->sc_type
== I2C_TYPE_SMBUS
) {
139 for (addr
= 0x09; addr
< 0x78; addr
++) {
141 * Skip certain i2c addresses:
142 * 0x00 General Call / START
144 * 0x02 Different Bus format
145 * 0x03 - 0x07 Reserved
147 * 0x0c Alert Response Address
148 * 0x28 ACCESS.Bus host
149 * 0x37 ACCESS.Bus default address
150 * 0x48 - 0x4b Prototypes
151 * 0x61 Device Default Address
152 * 0x78 - 0x7b 10-bit addresses
153 * 0x7c - 0x7f Reserved
155 * Some of these are skipped by judicious selection
156 * of the range of the above for (;;) statement.
158 * if (addr <= 0x08 || addr >= 0x78)
161 if (addr
== 0x0c || addr
== 0x28 || addr
== 0x37 ||
162 addr
== 0x61 || (addr
& 0x7c) == 0x48)
165 iic_acquire_bus(ic
, 0);
167 * Use SMBus quick_write command to detect most
168 * addresses; should avoid hanging the bus on
169 * some write-only devices (like clocks that show
170 * up at address 0x69)
172 * XXX The quick_write() is allegedly known to
173 * XXX corrupt the Atmel AT24RF08 EEPROM found
174 * XXX on some IBM Thinkpads!
176 if ((addr
& 0xf8) == 0x30 ||
177 (addr
& 0xf0) == 0x50)
178 err
= iic_smbus_receive_byte(ic
, addr
, &val
, 0);
180 err
= iic_smbus_quick_write(ic
, addr
, 0);
183 aprint_normal("%s: devices at",
186 aprint_normal(" 0x%02x", addr
);
188 iic_release_bus(ic
, 0);
191 aprint_normal("%s: no devices found", ic
->ic_devname
);
196 if (!pmf_device_register(self
, NULL
, NULL
))
197 aprint_error_dev(self
, "couldn't establish power handler\n");
200 * Attach all i2c devices described in the kernel
201 * configuration file.
203 config_search_ia(iic_search
, self
, "iic", NULL
);
207 iic_smbus_intr_thread(void *aux
)
210 struct ic_intr_list
*il
;
217 while (ic
->ic_running
) {
218 if (ic
->ic_pending
== 0)
219 rv
= tsleep(ic
, PZERO
, "iicintr", hz
);
220 if (ic
->ic_pending
> 0) {
221 LIST_FOREACH(il
, &(ic
->ic_proc_list
), il_next
) {
222 (*il
->il_intr
)(il
->il_intrarg
);
232 iic_smbus_intr_establish(i2c_tag_t ic
, int (*intr
)(void *), void *intrarg
)
234 struct ic_intr_list
*il
;
236 il
= malloc(sizeof(struct ic_intr_list
), M_DEVBUF
, M_WAITOK
);
241 il
->il_intrarg
= intrarg
;
243 LIST_INSERT_HEAD(&(ic
->ic_list
), il
, il_next
);
249 iic_smbus_intr_disestablish(i2c_tag_t ic
, void *hdl
)
251 struct ic_intr_list
*il
;
253 il
= (struct ic_intr_list
*)hdl
;
255 LIST_REMOVE(il
, il_next
);
262 iic_smbus_intr_establish_proc(i2c_tag_t ic
, int (*intr
)(void *), void *intrarg
)
264 struct ic_intr_list
*il
;
266 il
= malloc(sizeof(struct ic_intr_list
), M_DEVBUF
, M_WAITOK
);
271 il
->il_intrarg
= intrarg
;
273 LIST_INSERT_HEAD(&(ic
->ic_proc_list
), il
, il_next
);
279 iic_smbus_intr_disestablish_proc(i2c_tag_t ic
, void *hdl
)
281 struct ic_intr_list
*il
;
283 il
= (struct ic_intr_list
*)hdl
;
285 LIST_REMOVE(il
, il_next
);
292 iic_smbus_intr(i2c_tag_t ic
)
294 struct ic_intr_list
*il
;
296 LIST_FOREACH(il
, &(ic
->ic_list
), il_next
) {
297 (*il
->il_intr
)(il
->il_intrarg
);
306 CFATTACH_DECL_NEW(iic
, sizeof(struct iic_softc
),
307 iic_match
, iic_attach
, NULL
, NULL
);