i2c.c revision 1.97 1 1.97 thorpej /* $NetBSD: i2c.c,v 1.97 2025/09/16 14:28:11 thorpej Exp $ */
2 1.1 thorpej
3 1.1 thorpej /*
4 1.1 thorpej * Copyright (c) 2003 Wasabi Systems, Inc.
5 1.1 thorpej * All rights reserved.
6 1.1 thorpej *
7 1.1 thorpej * Written by Jason R. Thorpe for Wasabi Systems, Inc.
8 1.1 thorpej *
9 1.1 thorpej * Redistribution and use in source and binary forms, with or without
10 1.1 thorpej * modification, are permitted provided that the following conditions
11 1.1 thorpej * are met:
12 1.1 thorpej * 1. Redistributions of source code must retain the above copyright
13 1.1 thorpej * notice, this list of conditions and the following disclaimer.
14 1.1 thorpej * 2. Redistributions in binary form must reproduce the above copyright
15 1.1 thorpej * notice, this list of conditions and the following disclaimer in the
16 1.1 thorpej * documentation and/or other materials provided with the distribution.
17 1.1 thorpej * 3. All advertising materials mentioning features or use of this software
18 1.1 thorpej * must display the following acknowledgement:
19 1.1 thorpej * This product includes software developed for the NetBSD Project by
20 1.1 thorpej * Wasabi Systems, Inc.
21 1.1 thorpej * 4. The name of Wasabi Systems, Inc. may not be used to endorse
22 1.1 thorpej * or promote products derived from this software without specific prior
23 1.1 thorpej * written permission.
24 1.1 thorpej *
25 1.1 thorpej * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
26 1.1 thorpej * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
27 1.1 thorpej * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
28 1.1 thorpej * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
29 1.1 thorpej * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
30 1.1 thorpej * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
31 1.1 thorpej * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
32 1.1 thorpej * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
33 1.1 thorpej * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 1.1 thorpej * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
35 1.1 thorpej * POSSIBILITY OF SUCH DAMAGE.
36 1.1 thorpej */
37 1.1 thorpej
38 1.45 jmcneill #ifdef _KERNEL_OPT
39 1.45 jmcneill #include "opt_i2c.h"
40 1.81 thorpej
41 1.81 thorpej #include "opt_fdt.h"
42 1.81 thorpej #ifdef FDT
43 1.81 thorpej #define I2C_USE_FDT
44 1.81 thorpej #endif /* FDT */
45 1.81 thorpej
46 1.81 thorpej #if defined(__aarch64__) || defined(__amd64__)
47 1.81 thorpej #include "acpica.h"
48 1.81 thorpej #if NACPICA > 0
49 1.81 thorpej #define I2C_USE_ACPI
50 1.81 thorpej #endif /* NACPICA > 0 */
51 1.81 thorpej #endif /* __aarch64__ || __amd64__ */
52 1.81 thorpej
53 1.81 thorpej #endif /* _KERNEL_OPT */
54 1.45 jmcneill
55 1.18 lukem #include <sys/cdefs.h>
56 1.97 thorpej __KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.97 2025/09/16 14:28:11 thorpej Exp $");
57 1.18 lukem
58 1.1 thorpej #include <sys/param.h>
59 1.1 thorpej #include <sys/systm.h>
60 1.1 thorpej #include <sys/device.h>
61 1.1 thorpej #include <sys/event.h>
62 1.1 thorpej #include <sys/conf.h>
63 1.11 jmcneill #include <sys/malloc.h>
64 1.34 jmcneill #include <sys/kmem.h>
65 1.11 jmcneill #include <sys/kthread.h>
66 1.11 jmcneill #include <sys/proc.h>
67 1.11 jmcneill #include <sys/kernel.h>
68 1.32 jmcneill #include <sys/fcntl.h>
69 1.28 mbalmer #include <sys/module.h>
70 1.50 pgoyette #include <sys/once.h>
71 1.50 pgoyette #include <sys/mutex.h>
72 1.1 thorpej
73 1.81 thorpej #ifdef I2C_USE_ACPI
74 1.81 thorpej #include <dev/acpi/acpivar.h>
75 1.93 thorpej #include <dev/acpi/acpi_i2c.h>
76 1.81 thorpej #endif /* I2C_USE_ACPI */
77 1.81 thorpej
78 1.81 thorpej #ifdef I2C_USE_FDT
79 1.81 thorpej #include <dev/fdt/fdtvar.h>
80 1.95 thorpej #include <dev/fdt/fdt_i2c.h>
81 1.81 thorpej #endif /* I2C_USE_FDT */
82 1.81 thorpej
83 1.1 thorpej #include <dev/i2c/i2cvar.h>
84 1.1 thorpej
85 1.56 riastrad #include "ioconf.h"
86 1.1 thorpej #include "locators.h"
87 1.1 thorpej
88 1.45 jmcneill #ifndef I2C_MAX_ADDR
89 1.27 pgoyette #define I2C_MAX_ADDR 0x3ff /* 10-bit address, max */
90 1.45 jmcneill #endif
91 1.27 pgoyette
92 1.1 thorpej struct iic_softc {
93 1.61 thorpej device_t sc_dev;
94 1.1 thorpej i2c_tag_t sc_tag;
95 1.27 pgoyette device_t sc_devices[I2C_MAX_ADDR + 1];
96 1.1 thorpej };
97 1.1 thorpej
98 1.31 jmcneill static dev_type_open(iic_open);
99 1.31 jmcneill static dev_type_close(iic_close);
100 1.31 jmcneill static dev_type_ioctl(iic_ioctl);
101 1.31 jmcneill
102 1.50 pgoyette int iic_init(void);
103 1.50 pgoyette
104 1.50 pgoyette kmutex_t iic_mtx;
105 1.50 pgoyette int iic_refcnt;
106 1.50 pgoyette
107 1.50 pgoyette ONCE_DECL(iic_once);
108 1.50 pgoyette
109 1.31 jmcneill const struct cdevsw iic_cdevsw = {
110 1.43 dholland .d_open = iic_open,
111 1.43 dholland .d_close = iic_close,
112 1.43 dholland .d_read = noread,
113 1.43 dholland .d_write = nowrite,
114 1.43 dholland .d_ioctl = iic_ioctl,
115 1.43 dholland .d_stop = nostop,
116 1.43 dholland .d_tty = notty,
117 1.43 dholland .d_poll = nopoll,
118 1.43 dholland .d_mmap = nommap,
119 1.43 dholland .d_kqfilter = nokqfilter,
120 1.44 dholland .d_discard = nodiscard,
121 1.43 dholland .d_flag = D_OTHER
122 1.31 jmcneill };
123 1.31 jmcneill
124 1.24 martin static void iic_fill_compat(struct i2c_attach_args*, const char*,
125 1.24 martin size_t, char **);
126 1.11 jmcneill
127 1.1 thorpej static int
128 1.24 martin iic_print_direct(void *aux, const char *pnp)
129 1.24 martin {
130 1.24 martin struct i2c_attach_args *ia = aux;
131 1.24 martin
132 1.24 martin if (pnp != NULL)
133 1.88 thorpej aprint_normal("%s%s%s%s at %s addr 0x%02x",
134 1.62 thorpej ia->ia_name ? ia->ia_name : "(unknown)",
135 1.88 thorpej ia->ia_ncompat ? " (" : "",
136 1.88 thorpej ia->ia_ncompat ? ia->ia_compat[0] : "",
137 1.88 thorpej ia->ia_ncompat ? ")" : "",
138 1.62 thorpej pnp, ia->ia_addr);
139 1.24 martin else
140 1.24 martin aprint_normal(" addr 0x%02x", ia->ia_addr);
141 1.24 martin
142 1.24 martin return UNCONF;
143 1.24 martin }
144 1.24 martin
145 1.24 martin static int
146 1.10 christos iic_print(void *aux, const char *pnp)
147 1.1 thorpej {
148 1.1 thorpej struct i2c_attach_args *ia = aux;
149 1.1 thorpej
150 1.58 thorpej if (ia->ia_addr != (i2c_addr_t)IICCF_ADDR_DEFAULT)
151 1.6 jmcneill aprint_normal(" addr 0x%x", ia->ia_addr);
152 1.1 thorpej
153 1.30 mbalmer return UNCONF;
154 1.1 thorpej }
155 1.1 thorpej
156 1.61 thorpej static bool
157 1.61 thorpej iic_is_special_address(i2c_addr_t addr)
158 1.61 thorpej {
159 1.61 thorpej
160 1.61 thorpej /*
161 1.61 thorpej * See: https://www.i2c-bus.org/addressing/
162 1.61 thorpej */
163 1.61 thorpej
164 1.61 thorpej /* General Call (read) / Start Byte (write) */
165 1.61 thorpej if (addr == 0x00)
166 1.61 thorpej return (true);
167 1.61 thorpej
168 1.61 thorpej /* CBUS Addresses */
169 1.61 thorpej if (addr == 0x01)
170 1.61 thorpej return (true);
171 1.61 thorpej
172 1.61 thorpej /* Reserved for Different Bus Formats */
173 1.61 thorpej if (addr == 0x02)
174 1.61 thorpej return (true);
175 1.61 thorpej
176 1.61 thorpej /* Reserved for future purposes */
177 1.61 thorpej if (addr == 0x03)
178 1.61 thorpej return (true);
179 1.61 thorpej
180 1.61 thorpej /* High Speed Master Code */
181 1.61 thorpej if ((addr & 0x7c) == 0x04)
182 1.61 thorpej return (true);
183 1.61 thorpej
184 1.61 thorpej /* 10-bit Slave Addressing prefix */
185 1.61 thorpej if ((addr & 0x7c) == 0x78)
186 1.61 thorpej return (true);
187 1.92 riastrad
188 1.61 thorpej /* Reserved for future purposes */
189 1.61 thorpej if ((addr & 0x7c) == 0x7c)
190 1.61 thorpej return (true);
191 1.92 riastrad
192 1.61 thorpej return (false);
193 1.61 thorpej }
194 1.61 thorpej
195 1.61 thorpej static int
196 1.61 thorpej iic_probe_none(struct iic_softc *sc,
197 1.61 thorpej const struct i2c_attach_args *ia, int flags)
198 1.61 thorpej {
199 1.61 thorpej
200 1.61 thorpej return (0);
201 1.61 thorpej }
202 1.61 thorpej
203 1.61 thorpej static int
204 1.61 thorpej iic_probe_smbus_quick_write(struct iic_softc *sc,
205 1.61 thorpej const struct i2c_attach_args *ia, int flags)
206 1.61 thorpej {
207 1.61 thorpej int error;
208 1.61 thorpej
209 1.61 thorpej if ((error = iic_acquire_bus(ia->ia_tag, flags)) == 0) {
210 1.61 thorpej error = iic_smbus_quick_write(ia->ia_tag, ia->ia_addr, flags);
211 1.61 thorpej }
212 1.61 thorpej (void) iic_release_bus(ia->ia_tag, flags);
213 1.61 thorpej
214 1.61 thorpej return (error);
215 1.61 thorpej }
216 1.61 thorpej
217 1.61 thorpej static int
218 1.61 thorpej iic_probe_smbus_receive_byte(struct iic_softc *sc,
219 1.61 thorpej const struct i2c_attach_args *ia, int flags)
220 1.61 thorpej {
221 1.61 thorpej int error;
222 1.61 thorpej
223 1.61 thorpej if ((error = iic_acquire_bus(ia->ia_tag, flags)) == 0) {
224 1.61 thorpej uint8_t dummy;
225 1.61 thorpej
226 1.61 thorpej error = iic_smbus_receive_byte(ia->ia_tag, ia->ia_addr,
227 1.61 thorpej &dummy, flags);
228 1.61 thorpej }
229 1.61 thorpej (void) iic_release_bus(ia->ia_tag, flags);
230 1.61 thorpej
231 1.61 thorpej return (error);
232 1.61 thorpej }
233 1.61 thorpej
234 1.61 thorpej static bool
235 1.75 thorpej iic_indirect_driver_is_permitted(struct iic_softc *sc, cfdata_t cf)
236 1.61 thorpej {
237 1.61 thorpej prop_object_iterator_t iter;
238 1.75 thorpej prop_array_t permitlist;
239 1.61 thorpej prop_string_t pstr;
240 1.61 thorpej prop_type_t ptype;
241 1.61 thorpej bool rv = false;
242 1.61 thorpej
243 1.75 thorpej permitlist = prop_dictionary_get(device_properties(sc->sc_dev),
244 1.75 thorpej I2C_PROP_INDIRECT_DEVICE_PERMITLIST);
245 1.75 thorpej if (permitlist == NULL) {
246 1.75 thorpej /* No permitlist -> everything allowed */
247 1.61 thorpej return (true);
248 1.61 thorpej }
249 1.61 thorpej
250 1.75 thorpej if ((ptype = prop_object_type(permitlist)) != PROP_TYPE_ARRAY) {
251 1.61 thorpej aprint_error_dev(sc->sc_dev,
252 1.61 thorpej "invalid property type (%d) for '%s'; must be array (%d)\n",
253 1.75 thorpej ptype, I2C_PROP_INDIRECT_DEVICE_PERMITLIST,
254 1.75 thorpej PROP_TYPE_ARRAY);
255 1.61 thorpej return (false);
256 1.61 thorpej }
257 1.61 thorpej
258 1.75 thorpej iter = prop_array_iterator(permitlist);
259 1.61 thorpej while ((pstr = prop_object_iterator_next(iter)) != NULL) {
260 1.73 thorpej if (prop_string_equals_string(pstr, cf->cf_name)) {
261 1.61 thorpej rv = true;
262 1.61 thorpej break;
263 1.61 thorpej }
264 1.61 thorpej }
265 1.61 thorpej prop_object_iterator_release(iter);
266 1.61 thorpej
267 1.61 thorpej return (rv);
268 1.61 thorpej }
269 1.61 thorpej
270 1.1 thorpej static int
271 1.20 xtraeme iic_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
272 1.1 thorpej {
273 1.20 xtraeme struct iic_softc *sc = device_private(parent);
274 1.1 thorpej struct i2c_attach_args ia;
275 1.61 thorpej int (*probe_func)(struct iic_softc *,
276 1.61 thorpej const struct i2c_attach_args *, int);
277 1.61 thorpej prop_string_t pstr;
278 1.61 thorpej i2c_addr_t first_addr, last_addr;
279 1.1 thorpej
280 1.58 thorpej /*
281 1.61 thorpej * Before we do any more work, consult the allowed-driver
282 1.75 thorpej * permit-list for this bus (if any).
283 1.58 thorpej */
284 1.75 thorpej if (iic_indirect_driver_is_permitted(sc, cf) == false)
285 1.61 thorpej return (0);
286 1.61 thorpej
287 1.61 thorpej /* default to "quick write". */
288 1.61 thorpej probe_func = iic_probe_smbus_quick_write;
289 1.61 thorpej
290 1.61 thorpej pstr = prop_dictionary_get(device_properties(sc->sc_dev),
291 1.61 thorpej I2C_PROP_INDIRECT_PROBE_STRATEGY);
292 1.61 thorpej if (pstr == NULL) {
293 1.61 thorpej /* Use the default. */
294 1.73 thorpej } else if (prop_string_equals_string(pstr,
295 1.61 thorpej I2C_PROBE_STRATEGY_QUICK_WRITE)) {
296 1.61 thorpej probe_func = iic_probe_smbus_quick_write;
297 1.73 thorpej } else if (prop_string_equals_string(pstr,
298 1.61 thorpej I2C_PROBE_STRATEGY_RECEIVE_BYTE)) {
299 1.61 thorpej probe_func = iic_probe_smbus_receive_byte;
300 1.73 thorpej } else if (prop_string_equals_string(pstr,
301 1.61 thorpej I2C_PROBE_STRATEGY_NONE)) {
302 1.61 thorpej probe_func = iic_probe_none;
303 1.61 thorpej } else {
304 1.61 thorpej aprint_error_dev(sc->sc_dev,
305 1.61 thorpej "unknown probe strategy '%s'; defaulting to '%s'\n",
306 1.73 thorpej prop_string_value(pstr),
307 1.61 thorpej I2C_PROBE_STRATEGY_QUICK_WRITE);
308 1.61 thorpej
309 1.61 thorpej /* Use the default. */
310 1.61 thorpej }
311 1.58 thorpej
312 1.1 thorpej ia.ia_tag = sc->sc_tag;
313 1.1 thorpej
314 1.25 njoly ia.ia_name = NULL;
315 1.25 njoly ia.ia_ncompat = 0;
316 1.25 njoly ia.ia_compat = NULL;
317 1.57 bouyer ia.ia_prop = NULL;
318 1.25 njoly
319 1.61 thorpej if (cf->cf_loc[IICCF_ADDR] == IICCF_ADDR_DEFAULT) {
320 1.61 thorpej /*
321 1.61 thorpej * This particular config directive has
322 1.61 thorpej * wildcarded the address, so we will
323 1.61 thorpej * scan the entire bus for it.
324 1.61 thorpej */
325 1.61 thorpej first_addr = 0;
326 1.61 thorpej last_addr = I2C_MAX_ADDR;
327 1.61 thorpej } else {
328 1.61 thorpej /*
329 1.61 thorpej * This config directive hard-wires the i2c
330 1.61 thorpej * bus address for the device, so there is
331 1.61 thorpej * no need to go poking around at any other
332 1.61 thorpej * addresses.
333 1.61 thorpej */
334 1.61 thorpej if (cf->cf_loc[IICCF_ADDR] < 0 ||
335 1.61 thorpej cf->cf_loc[IICCF_ADDR] > I2C_MAX_ADDR) {
336 1.61 thorpej /* Invalid config directive! */
337 1.61 thorpej return (0);
338 1.61 thorpej }
339 1.61 thorpej first_addr = last_addr = cf->cf_loc[IICCF_ADDR];
340 1.61 thorpej }
341 1.61 thorpej
342 1.61 thorpej for (ia.ia_addr = first_addr; ia.ia_addr <= last_addr; ia.ia_addr++) {
343 1.61 thorpej int error, match_result;
344 1.61 thorpej
345 1.61 thorpej /*
346 1.61 thorpej * Skip I2C addresses that are reserved for
347 1.61 thorpej * special purposes.
348 1.61 thorpej */
349 1.61 thorpej if (iic_is_special_address(ia.ia_addr))
350 1.61 thorpej continue;
351 1.61 thorpej
352 1.61 thorpej /*
353 1.61 thorpej * Skip addresses where a device is already attached.
354 1.61 thorpej */
355 1.40 soren if (sc->sc_devices[ia.ia_addr] != NULL)
356 1.40 soren continue;
357 1.40 soren
358 1.61 thorpej /*
359 1.61 thorpej * Call the "match" routine for the device. If that
360 1.61 thorpej * returns success, then call the probe strategy
361 1.61 thorpej * function.
362 1.61 thorpej *
363 1.61 thorpej * We do it in this order because i2c devices tend
364 1.61 thorpej * to be found at a small number of possible addresses
365 1.61 thorpej * (e.g. read-time clocks that are only ever found at
366 1.61 thorpej * 0x68). This gives the driver a chance to skip any
367 1.61 thorpej * address that are not valid for the device, saving
368 1.61 thorpej * us from having to poke at the bus to see if anything
369 1.61 thorpej * is there.
370 1.61 thorpej */
371 1.78 thorpej match_result = config_probe(parent, cf, &ia);/*XXX*/
372 1.61 thorpej if (match_result <= 0)
373 1.61 thorpej continue;
374 1.61 thorpej
375 1.61 thorpej /*
376 1.61 thorpej * If the quality of the match by the driver was low
377 1.61 thorpej * (i.e. matched on being a valid address only, didn't
378 1.61 thorpej * perform any hardware probe), invoke our probe routine
379 1.61 thorpej * to see if it looks like something is really there.
380 1.61 thorpej */
381 1.61 thorpej if (match_result == I2C_MATCH_ADDRESS_ONLY &&
382 1.72 thorpej (error = (*probe_func)(sc, &ia, 0)) != 0)
383 1.40 soren continue;
384 1.40 soren
385 1.61 thorpej sc->sc_devices[ia.ia_addr] =
386 1.80 thorpej config_attach(parent, cf, &ia, iic_print, CFARGS_NONE);
387 1.27 pgoyette }
388 1.40 soren
389 1.30 mbalmer return 0;
390 1.1 thorpej }
391 1.1 thorpej
392 1.27 pgoyette static void
393 1.27 pgoyette iic_child_detach(device_t parent, device_t child)
394 1.27 pgoyette {
395 1.27 pgoyette struct iic_softc *sc = device_private(parent);
396 1.27 pgoyette int i;
397 1.27 pgoyette
398 1.27 pgoyette for (i = 0; i <= I2C_MAX_ADDR; i++)
399 1.27 pgoyette if (sc->sc_devices[i] == child) {
400 1.27 pgoyette sc->sc_devices[i] = NULL;
401 1.27 pgoyette break;
402 1.40 soren }
403 1.27 pgoyette }
404 1.27 pgoyette
405 1.1 thorpej static int
406 1.26 jmcneill iic_rescan(device_t self, const char *ifattr, const int *locators)
407 1.26 jmcneill {
408 1.78 thorpej config_search(self, NULL,
409 1.80 thorpej CFARGS(.search = iic_search,
410 1.80 thorpej .locators = locators));
411 1.26 jmcneill return 0;
412 1.26 jmcneill }
413 1.26 jmcneill
414 1.26 jmcneill static int
415 1.20 xtraeme iic_match(device_t parent, cfdata_t cf, void *aux)
416 1.1 thorpej {
417 1.1 thorpej
418 1.30 mbalmer return 1;
419 1.1 thorpej }
420 1.1 thorpej
421 1.97 thorpej static bool
422 1.97 thorpej iic_attach_children_direct(struct iic_softc *sc)
423 1.1 thorpej {
424 1.97 thorpej device_t parent = device_parent(sc->sc_dev);
425 1.97 thorpej devhandle_t devhandle = device_handle(sc->sc_dev);
426 1.95 thorpej prop_array_t child_devices;
427 1.97 thorpej i2c_tag_t ic = sc->sc_tag;
428 1.95 thorpej bool no_indirect_config;
429 1.1 thorpej
430 1.95 thorpej child_devices = prop_dictionary_get(device_properties(parent),
431 1.95 thorpej "i2c-child-devices");
432 1.95 thorpej if (!prop_dictionary_get_bool(device_properties(parent),
433 1.95 thorpej "i2c-no-indirect-config",
434 1.95 thorpej &no_indirect_config)) {
435 1.95 thorpej no_indirect_config = false;
436 1.95 thorpej }
437 1.95 thorpej
438 1.97 thorpej if (child_devices == NULL) {
439 1.95 thorpej switch (devhandle_type(devhandle)) {
440 1.93 thorpej #ifdef I2C_USE_ACPI
441 1.95 thorpej case DEVHANDLE_TYPE_ACPI:
442 1.97 thorpej child_devices = acpi_copy_i2c_devs(sc->sc_dev);
443 1.95 thorpej no_indirect_config = true;
444 1.95 thorpej break;
445 1.93 thorpej #endif
446 1.95 thorpej #ifdef I2C_USE_FDT
447 1.95 thorpej case DEVHANDLE_TYPE_OF:
448 1.97 thorpej child_devices = fdtbus_copy_i2c_devs(sc->sc_dev);
449 1.93 thorpej no_indirect_config = true;
450 1.95 thorpej break;
451 1.95 thorpej #endif
452 1.95 thorpej default:
453 1.95 thorpej break;
454 1.93 thorpej }
455 1.97 thorpej } else {
456 1.97 thorpej prop_object_retain(child_devices);
457 1.51 jmcneill }
458 1.51 jmcneill
459 1.24 martin if (child_devices) {
460 1.24 martin unsigned int i, count;
461 1.24 martin prop_dictionary_t dev;
462 1.24 martin prop_data_t cdata;
463 1.66 thorpej uint32_t addr;
464 1.24 martin uint64_t cookie;
465 1.77 jmcneill uint32_t cookietype;
466 1.24 martin const char *name;
467 1.97 thorpej char *buf;
468 1.24 martin struct i2c_attach_args ia;
469 1.93 thorpej devhandle_t child_devhandle;
470 1.53 jakllsch int loc[IICCF_NLOCS];
471 1.24 martin
472 1.24 martin memset(loc, 0, sizeof loc);
473 1.24 martin count = prop_array_count(child_devices);
474 1.24 martin for (i = 0; i < count; i++) {
475 1.24 martin dev = prop_array_get(child_devices, i);
476 1.24 martin if (!dev) continue;
477 1.79 christos if (!prop_dictionary_get_string(
478 1.62 thorpej dev, "name", &name)) {
479 1.62 thorpej /* "name" property is optional. */
480 1.62 thorpej name = NULL;
481 1.62 thorpej }
482 1.24 martin if (!prop_dictionary_get_uint32(dev, "addr", &addr))
483 1.24 martin continue;
484 1.24 martin if (!prop_dictionary_get_uint64(dev, "cookie", &cookie))
485 1.24 martin cookie = 0;
486 1.77 jmcneill if (!prop_dictionary_get_uint32(dev, "cookietype",
487 1.77 jmcneill &cookietype))
488 1.77 jmcneill cookietype = I2C_COOKIE_NONE;
489 1.53 jakllsch loc[IICCF_ADDR] = addr;
490 1.24 martin
491 1.24 martin memset(&ia, 0, sizeof ia);
492 1.24 martin ia.ia_addr = addr;
493 1.24 martin ia.ia_tag = ic;
494 1.24 martin ia.ia_name = name;
495 1.24 martin ia.ia_cookie = cookie;
496 1.77 jmcneill ia.ia_cookietype = cookietype;
497 1.57 bouyer ia.ia_prop = dev;
498 1.24 martin
499 1.93 thorpej child_devhandle = devhandle_invalid();
500 1.81 thorpej #ifdef I2C_USE_FDT
501 1.81 thorpej if (cookietype == I2C_COOKIE_OF) {
502 1.93 thorpej child_devhandle =
503 1.93 thorpej devhandle_from_of(devhandle,
504 1.93 thorpej (int)cookie);
505 1.81 thorpej }
506 1.81 thorpej #endif /* I2C_USE_FDT */
507 1.81 thorpej #ifdef I2C_USE_ACPI
508 1.81 thorpej if (cookietype == I2C_COOKIE_ACPI) {
509 1.93 thorpej child_devhandle =
510 1.83 thorpej devhandle_from_acpi(devhandle,
511 1.83 thorpej (ACPI_HANDLE)cookie);
512 1.81 thorpej }
513 1.81 thorpej #endif /* I2C_USE_ACPI */
514 1.81 thorpej
515 1.24 martin buf = NULL;
516 1.24 martin cdata = prop_dictionary_get(dev, "compatible");
517 1.24 martin if (cdata)
518 1.24 martin iic_fill_compat(&ia,
519 1.73 thorpej prop_data_value(cdata),
520 1.24 martin prop_data_size(cdata), &buf);
521 1.24 martin
522 1.62 thorpej if (name == NULL && cdata == NULL) {
523 1.97 thorpej aprint_error_dev(sc->sc_dev,
524 1.62 thorpej "WARNING: ignoring bad child device entry "
525 1.62 thorpej "for address 0x%02x\n", addr);
526 1.62 thorpej } else {
527 1.62 thorpej if (addr > I2C_MAX_ADDR) {
528 1.97 thorpej aprint_error_dev(sc->sc_dev,
529 1.62 thorpej "WARNING: ignoring bad device "
530 1.62 thorpej "address @ 0x%02x\n", addr);
531 1.62 thorpej } else if (sc->sc_devices[addr] == NULL) {
532 1.62 thorpej sc->sc_devices[addr] =
533 1.97 thorpej config_found(sc->sc_dev, &ia,
534 1.78 thorpej iic_print_direct,
535 1.81 thorpej CFARGS(.locators = loc,
536 1.93 thorpej .devhandle = child_devhandle));
537 1.62 thorpej }
538 1.33 jmcneill }
539 1.24 martin
540 1.24 martin if (ia.ia_compat)
541 1.24 martin free(ia.ia_compat, M_TEMP);
542 1.24 martin if (buf)
543 1.24 martin free(buf, M_TEMP);
544 1.24 martin }
545 1.93 thorpej prop_object_release(child_devices);
546 1.93 thorpej child_devices = NULL;
547 1.97 thorpej }
548 1.97 thorpej
549 1.97 thorpej /*
550 1.97 thorpej * We return "true" if we want to let indirect configuration
551 1.97 thorpej * proceed.
552 1.97 thorpej */
553 1.97 thorpej return !no_indirect_config;
554 1.97 thorpej }
555 1.97 thorpej
556 1.97 thorpej static void
557 1.97 thorpej iic_attach(device_t parent, device_t self, void *aux)
558 1.97 thorpej {
559 1.97 thorpej struct iic_softc *sc = device_private(self);
560 1.97 thorpej devhandle_t devhandle = device_handle(self);
561 1.97 thorpej struct i2cbus_attach_args *iba = aux;
562 1.97 thorpej
563 1.97 thorpej aprint_naive("\n");
564 1.97 thorpej aprint_normal(": I2C bus\n");
565 1.97 thorpej
566 1.97 thorpej sc->sc_dev = self;
567 1.97 thorpej sc->sc_tag = iba->iba_tag;
568 1.97 thorpej
569 1.97 thorpej if (!pmf_device_register(self, NULL, NULL))
570 1.97 thorpej aprint_error_dev(self, "couldn't establish power handler\n");
571 1.97 thorpej
572 1.97 thorpej /* XXX There ought to be a generic way to do this. */
573 1.97 thorpej switch (devhandle_type(devhandle)) {
574 1.97 thorpej #ifdef I2C_USE_ACPI
575 1.97 thorpej case DEVHANDLE_TYPE_ACPI:
576 1.97 thorpej acpi_i2c_register(self, sc->sc_tag);
577 1.97 thorpej break;
578 1.97 thorpej #endif
579 1.97 thorpej #ifdef I2C_USE_FDT
580 1.97 thorpej case DEVHANDLE_TYPE_OF:
581 1.97 thorpej fdtbus_register_i2c_controller(self, sc->sc_tag);
582 1.97 thorpej break;
583 1.97 thorpej #endif
584 1.97 thorpej default:
585 1.97 thorpej break;
586 1.97 thorpej }
587 1.97 thorpej
588 1.97 thorpej if (iic_attach_children_direct(sc)) {
589 1.24 martin /*
590 1.24 martin * Attach all i2c devices described in the kernel
591 1.24 martin * configuration file.
592 1.24 martin */
593 1.26 jmcneill iic_rescan(self, "iic", NULL);
594 1.24 martin }
595 1.1 thorpej }
596 1.1 thorpej
597 1.33 jmcneill static int
598 1.33 jmcneill iic_detach(device_t self, int flags)
599 1.33 jmcneill {
600 1.90 riastrad int error;
601 1.33 jmcneill
602 1.90 riastrad error = config_detach_children(self, flags);
603 1.90 riastrad if (error)
604 1.90 riastrad return error;
605 1.33 jmcneill
606 1.33 jmcneill pmf_device_deregister(self);
607 1.33 jmcneill
608 1.33 jmcneill return 0;
609 1.33 jmcneill }
610 1.33 jmcneill
611 1.11 jmcneill static void
612 1.24 martin iic_fill_compat(struct i2c_attach_args *ia, const char *compat, size_t len,
613 1.24 martin char **buffer)
614 1.24 martin {
615 1.24 martin int count, i;
616 1.24 martin const char *c, *start, **ptr;
617 1.24 martin
618 1.24 martin *buffer = NULL;
619 1.24 martin for (i = count = 0, c = compat; i < len; i++, c++)
620 1.24 martin if (*c == 0)
621 1.24 martin count++;
622 1.24 martin count += 2;
623 1.24 martin ptr = malloc(sizeof(char*)*count, M_TEMP, M_WAITOK);
624 1.24 martin if (!ptr) return;
625 1.24 martin
626 1.24 martin for (i = count = 0, start = c = compat; i < len; i++, c++) {
627 1.24 martin if (*c == 0) {
628 1.24 martin ptr[count++] = start;
629 1.24 martin start = c+1;
630 1.24 martin }
631 1.24 martin }
632 1.24 martin if (start < compat+len) {
633 1.24 martin /* last string not 0 terminated */
634 1.24 martin size_t l = c-start;
635 1.24 martin *buffer = malloc(l+1, M_TEMP, M_WAITOK);
636 1.24 martin memcpy(*buffer, start, l);
637 1.24 martin (*buffer)[l] = 0;
638 1.24 martin ptr[count++] = *buffer;
639 1.24 martin }
640 1.24 martin ptr[count] = NULL;
641 1.24 martin
642 1.24 martin ia->ia_compat = ptr;
643 1.24 martin ia->ia_ncompat = count;
644 1.24 martin }
645 1.24 martin
646 1.62 thorpej /*
647 1.63 thorpej * iic_compatible_match --
648 1.62 thorpej * Match a device's "compatible" property against the list
649 1.63 thorpej * of compatible strings provided by the driver.
650 1.62 thorpej */
651 1.65 thorpej int
652 1.63 thorpej iic_compatible_match(const struct i2c_attach_args *ia,
653 1.76 thorpej const struct device_compatible_entry *compats)
654 1.63 thorpej {
655 1.65 thorpej int match_result;
656 1.63 thorpej
657 1.65 thorpej match_result = device_compatible_match(ia->ia_compat, ia->ia_ncompat,
658 1.76 thorpej compats);
659 1.65 thorpej if (match_result) {
660 1.65 thorpej match_result =
661 1.65 thorpej MIN(I2C_MATCH_DIRECT_COMPATIBLE + match_result - 1,
662 1.65 thorpej I2C_MATCH_DIRECT_COMPATIBLE_MAX);
663 1.63 thorpej }
664 1.62 thorpej
665 1.65 thorpej return match_result;
666 1.62 thorpej }
667 1.62 thorpej
668 1.63 thorpej /*
669 1.76 thorpej * iic_compatible_lookup --
670 1.76 thorpej * Look the compatible entry that matches one of the driver's
671 1.76 thorpej * "compatible" strings. The first match is returned.
672 1.76 thorpej */
673 1.76 thorpej const struct device_compatible_entry *
674 1.76 thorpej iic_compatible_lookup(const struct i2c_attach_args *ia,
675 1.76 thorpej const struct device_compatible_entry *compats)
676 1.76 thorpej {
677 1.76 thorpej return device_compatible_lookup(ia->ia_compat, ia->ia_ncompat,
678 1.76 thorpej compats);
679 1.76 thorpej }
680 1.76 thorpej
681 1.76 thorpej /*
682 1.63 thorpej * iic_use_direct_match --
683 1.63 thorpej * Helper for direct-config of i2c. Returns true if this is
684 1.84 andvar * a direct-config situation, along with match result.
685 1.63 thorpej * Returns false if the driver should use indirect-config
686 1.63 thorpej * matching logic.
687 1.63 thorpej */
688 1.62 thorpej bool
689 1.62 thorpej iic_use_direct_match(const struct i2c_attach_args *ia, const cfdata_t cf,
690 1.63 thorpej const struct device_compatible_entry *compats,
691 1.63 thorpej int *match_resultp)
692 1.62 thorpej {
693 1.62 thorpej KASSERT(match_resultp != NULL);
694 1.62 thorpej
695 1.62 thorpej if (ia->ia_name != NULL &&
696 1.62 thorpej strcmp(ia->ia_name, cf->cf_name) == 0) {
697 1.62 thorpej *match_resultp = I2C_MATCH_DIRECT_SPECIFIC;
698 1.62 thorpej return true;
699 1.62 thorpej }
700 1.62 thorpej
701 1.62 thorpej if (ia->ia_ncompat > 0 && ia->ia_compat != NULL) {
702 1.76 thorpej *match_resultp = iic_compatible_match(ia, compats);
703 1.70 mlelstv return true;
704 1.62 thorpej }
705 1.62 thorpej
706 1.62 thorpej return false;
707 1.24 martin }
708 1.24 martin
709 1.31 jmcneill static int
710 1.31 jmcneill iic_open(dev_t dev, int flag, int fmt, lwp_t *l)
711 1.31 jmcneill {
712 1.31 jmcneill struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev));
713 1.31 jmcneill
714 1.50 pgoyette mutex_enter(&iic_mtx);
715 1.50 pgoyette if (sc == NULL) {
716 1.50 pgoyette mutex_exit(&iic_mtx);
717 1.31 jmcneill return ENXIO;
718 1.50 pgoyette }
719 1.50 pgoyette iic_refcnt++;
720 1.50 pgoyette mutex_exit(&iic_mtx);
721 1.31 jmcneill
722 1.31 jmcneill return 0;
723 1.31 jmcneill }
724 1.31 jmcneill
725 1.31 jmcneill static int
726 1.31 jmcneill iic_close(dev_t dev, int flag, int fmt, lwp_t *l)
727 1.31 jmcneill {
728 1.50 pgoyette
729 1.50 pgoyette mutex_enter(&iic_mtx);
730 1.50 pgoyette iic_refcnt--;
731 1.50 pgoyette mutex_exit(&iic_mtx);
732 1.50 pgoyette
733 1.31 jmcneill return 0;
734 1.31 jmcneill }
735 1.31 jmcneill
736 1.31 jmcneill static int
737 1.32 jmcneill iic_ioctl_exec(struct iic_softc *sc, i2c_ioctl_exec_t *iie, int flag)
738 1.31 jmcneill {
739 1.31 jmcneill i2c_tag_t ic = sc->sc_tag;
740 1.87 mlelstv uint8_t *buf = NULL;
741 1.34 jmcneill void *cmd = NULL;
742 1.92 riastrad int error = 0;
743 1.31 jmcneill
744 1.31 jmcneill /* Validate parameters */
745 1.31 jmcneill if (iie->iie_addr > I2C_MAX_ADDR)
746 1.31 jmcneill return EINVAL;
747 1.31 jmcneill if (iie->iie_cmdlen > I2C_EXEC_MAX_CMDLEN ||
748 1.31 jmcneill iie->iie_buflen > I2C_EXEC_MAX_BUFLEN)
749 1.31 jmcneill return EINVAL;
750 1.31 jmcneill if (iie->iie_cmd != NULL && iie->iie_cmdlen == 0)
751 1.31 jmcneill return EINVAL;
752 1.31 jmcneill if (iie->iie_buf != NULL && iie->iie_buflen == 0)
753 1.31 jmcneill return EINVAL;
754 1.32 jmcneill if (I2C_OP_WRITE_P(iie->iie_op) && (flag & FWRITE) == 0)
755 1.32 jmcneill return EBADF;
756 1.31 jmcneill
757 1.31 jmcneill #if 0
758 1.31 jmcneill /* Disallow userspace access to devices that have drivers attached. */
759 1.31 jmcneill if (sc->sc_devices[iie->iie_addr] != NULL)
760 1.31 jmcneill return EBUSY;
761 1.31 jmcneill #endif
762 1.31 jmcneill
763 1.31 jmcneill if (iie->iie_cmd != NULL) {
764 1.34 jmcneill cmd = kmem_alloc(iie->iie_cmdlen, KM_SLEEP);
765 1.31 jmcneill error = copyin(iie->iie_cmd, cmd, iie->iie_cmdlen);
766 1.48 christos if (error)
767 1.48 christos goto out;
768 1.31 jmcneill }
769 1.31 jmcneill
770 1.87 mlelstv if (iie->iie_buf != NULL) {
771 1.87 mlelstv buf = kmem_alloc(iie->iie_buflen, KM_SLEEP);
772 1.87 mlelstv if (I2C_OP_WRITE_P(iie->iie_op)) {
773 1.87 mlelstv error = copyin(iie->iie_buf, buf, iie->iie_buflen);
774 1.87 mlelstv if (error)
775 1.87 mlelstv goto out;
776 1.87 mlelstv }
777 1.46 jakllsch }
778 1.46 jakllsch
779 1.31 jmcneill iic_acquire_bus(ic, 0);
780 1.31 jmcneill error = iic_exec(ic, iie->iie_op, iie->iie_addr, cmd, iie->iie_cmdlen,
781 1.31 jmcneill buf, iie->iie_buflen, 0);
782 1.31 jmcneill iic_release_bus(ic, 0);
783 1.31 jmcneill
784 1.36 jmcneill /*
785 1.36 jmcneill * Some drivers return error codes on failure, and others return -1.
786 1.36 jmcneill */
787 1.36 jmcneill if (error < 0)
788 1.36 jmcneill error = EIO;
789 1.36 jmcneill
790 1.48 christos out:
791 1.91 brad if (!error && iie->iie_buf != NULL && I2C_OP_READ_P(iie->iie_op))
792 1.87 mlelstv error = copyout(buf, iie->iie_buf, iie->iie_buflen);
793 1.87 mlelstv
794 1.87 mlelstv if (buf)
795 1.87 mlelstv kmem_free(buf, iie->iie_buflen);
796 1.87 mlelstv
797 1.34 jmcneill if (cmd)
798 1.34 jmcneill kmem_free(cmd, iie->iie_cmdlen);
799 1.34 jmcneill
800 1.31 jmcneill return error;
801 1.31 jmcneill }
802 1.31 jmcneill
803 1.31 jmcneill static int
804 1.31 jmcneill iic_ioctl(dev_t dev, u_long cmd, void *data, int flag, lwp_t *l)
805 1.31 jmcneill {
806 1.31 jmcneill struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev));
807 1.31 jmcneill
808 1.31 jmcneill if (sc == NULL)
809 1.31 jmcneill return ENXIO;
810 1.31 jmcneill
811 1.31 jmcneill switch (cmd) {
812 1.31 jmcneill case I2C_IOCTL_EXEC:
813 1.32 jmcneill return iic_ioctl_exec(sc, (i2c_ioctl_exec_t *)data, flag);
814 1.31 jmcneill default:
815 1.31 jmcneill return ENODEV;
816 1.31 jmcneill }
817 1.31 jmcneill }
818 1.31 jmcneill
819 1.24 martin
820 1.67 jdolecek CFATTACH_DECL3_NEW(iic, sizeof(struct iic_softc),
821 1.67 jdolecek iic_match, iic_attach, iic_detach, NULL, iic_rescan, iic_child_detach,
822 1.67 jdolecek DVF_DETACH_SHUTDOWN);
823 1.28 mbalmer
824 1.86 pgoyette MODULE(MODULE_CLASS_DRIVER, iic, "i2cexec,i2c_bitbang,i2c_subr");
825 1.28 mbalmer
826 1.28 mbalmer #ifdef _MODULE
827 1.28 mbalmer #include "ioconf.c"
828 1.28 mbalmer #endif
829 1.28 mbalmer
830 1.50 pgoyette int
831 1.50 pgoyette iic_init(void)
832 1.50 pgoyette {
833 1.50 pgoyette
834 1.50 pgoyette mutex_init(&iic_mtx, MUTEX_DEFAULT, IPL_NONE);
835 1.50 pgoyette iic_refcnt = 0;
836 1.50 pgoyette return 0;
837 1.50 pgoyette }
838 1.50 pgoyette
839 1.28 mbalmer static int
840 1.28 mbalmer iic_modcmd(modcmd_t cmd, void *opaque)
841 1.28 mbalmer {
842 1.50 pgoyette #ifdef _MODULE
843 1.50 pgoyette int bmajor, cmajor;
844 1.50 pgoyette #endif
845 1.28 mbalmer int error;
846 1.28 mbalmer
847 1.28 mbalmer error = 0;
848 1.28 mbalmer switch (cmd) {
849 1.28 mbalmer case MODULE_CMD_INIT:
850 1.50 pgoyette RUN_ONCE(&iic_once, iic_init);
851 1.50 pgoyette
852 1.28 mbalmer #ifdef _MODULE
853 1.50 pgoyette mutex_enter(&iic_mtx);
854 1.50 pgoyette bmajor = cmajor = -1;
855 1.50 pgoyette error = devsw_attach("iic", NULL, &bmajor,
856 1.50 pgoyette &iic_cdevsw, &cmajor);
857 1.50 pgoyette if (error != 0) {
858 1.50 pgoyette mutex_exit(&iic_mtx);
859 1.50 pgoyette break;
860 1.50 pgoyette }
861 1.28 mbalmer error = config_init_component(cfdriver_ioconf_iic,
862 1.28 mbalmer cfattach_ioconf_iic, cfdata_ioconf_iic);
863 1.50 pgoyette if (error) {
864 1.28 mbalmer aprint_error("%s: unable to init component\n",
865 1.28 mbalmer iic_cd.cd_name);
866 1.85 riastrad devsw_detach(NULL, &iic_cdevsw);
867 1.50 pgoyette }
868 1.50 pgoyette mutex_exit(&iic_mtx);
869 1.28 mbalmer #endif
870 1.28 mbalmer break;
871 1.28 mbalmer case MODULE_CMD_FINI:
872 1.50 pgoyette mutex_enter(&iic_mtx);
873 1.50 pgoyette if (iic_refcnt != 0) {
874 1.50 pgoyette mutex_exit(&iic_mtx);
875 1.50 pgoyette return EBUSY;
876 1.50 pgoyette }
877 1.28 mbalmer #ifdef _MODULE
878 1.50 pgoyette error = config_fini_component(cfdriver_ioconf_iic,
879 1.28 mbalmer cfattach_ioconf_iic, cfdata_ioconf_iic);
880 1.50 pgoyette if (error != 0) {
881 1.50 pgoyette mutex_exit(&iic_mtx);
882 1.50 pgoyette break;
883 1.50 pgoyette }
884 1.85 riastrad devsw_detach(NULL, &iic_cdevsw);
885 1.28 mbalmer #endif
886 1.50 pgoyette mutex_exit(&iic_mtx);
887 1.28 mbalmer break;
888 1.28 mbalmer default:
889 1.28 mbalmer error = ENOTTY;
890 1.28 mbalmer }
891 1.28 mbalmer return error;
892 1.28 mbalmer }
893