Home | History | Annotate | Line # | Download | only in i2c
      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