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