11961a14aSEmmanuel Vadot /*- 21961a14aSEmmanuel Vadot * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG 31961a14aSEmmanuel Vadot * 41961a14aSEmmanuel Vadot * Redistribution and use in source and binary forms, with or without 51961a14aSEmmanuel Vadot * modification, are permitted provided that the following conditions 61961a14aSEmmanuel Vadot * are met: 71961a14aSEmmanuel Vadot * 1. Redistributions of source code must retain the above copyright 81961a14aSEmmanuel Vadot * notice, this list of conditions and the following disclaimer. 91961a14aSEmmanuel Vadot * 2. Redistributions in binary form must reproduce the above copyright 101961a14aSEmmanuel Vadot * notice, this list of conditions and the following disclaimer in the 111961a14aSEmmanuel Vadot * documentation and/or other materials provided with the distribution. 121961a14aSEmmanuel Vadot * 131961a14aSEmmanuel Vadot * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 141961a14aSEmmanuel Vadot * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 151961a14aSEmmanuel Vadot * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 161961a14aSEmmanuel Vadot * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 171961a14aSEmmanuel Vadot * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 181961a14aSEmmanuel Vadot * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 191961a14aSEmmanuel Vadot * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 201961a14aSEmmanuel Vadot * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 211961a14aSEmmanuel Vadot * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 221961a14aSEmmanuel Vadot * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 231961a14aSEmmanuel Vadot * SUCH DAMAGE. 241961a14aSEmmanuel Vadot * 251961a14aSEmmanuel Vadot */ 261961a14aSEmmanuel Vadot 271961a14aSEmmanuel Vadot #include <sys/param.h> 281961a14aSEmmanuel Vadot #include <sys/systm.h> 291961a14aSEmmanuel Vadot #include <sys/bus.h> 301961a14aSEmmanuel Vadot #include <sys/malloc.h> 311961a14aSEmmanuel Vadot 321961a14aSEmmanuel Vadot #include <dev/iicbus/iicbus.h> 331961a14aSEmmanuel Vadot #include <dev/iicbus/iiconf.h> 341961a14aSEmmanuel Vadot 351961a14aSEmmanuel Vadot #include <linux/device.h> 361961a14aSEmmanuel Vadot #include <linux/i2c.h> 371961a14aSEmmanuel Vadot #include <linux/i2c-algo-bit.h> 381961a14aSEmmanuel Vadot #include <linux/list.h> 391961a14aSEmmanuel Vadot #include <linux/pci.h> 401961a14aSEmmanuel Vadot 411961a14aSEmmanuel Vadot #include "iicbus_if.h" 421961a14aSEmmanuel Vadot #include "iicbb_if.h" 431961a14aSEmmanuel Vadot #include "lkpi_iic_if.h" 441961a14aSEmmanuel Vadot 451961a14aSEmmanuel Vadot static int lkpi_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs); 461961a14aSEmmanuel Vadot static int lkpi_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr); 471961a14aSEmmanuel Vadot 481961a14aSEmmanuel Vadot struct lkpi_iic_softc { 491961a14aSEmmanuel Vadot device_t iicbus; 501961a14aSEmmanuel Vadot struct i2c_adapter *adapter; 511961a14aSEmmanuel Vadot }; 521961a14aSEmmanuel Vadot 5325d21a84SEmmanuel Vadot static struct sx lkpi_sx_i2c; 5425d21a84SEmmanuel Vadot 5525d21a84SEmmanuel Vadot static void 5625d21a84SEmmanuel Vadot lkpi_sysinit_i2c(void *arg __unused) 5725d21a84SEmmanuel Vadot { 5825d21a84SEmmanuel Vadot 5925d21a84SEmmanuel Vadot sx_init(&lkpi_sx_i2c, "lkpi-i2c"); 6025d21a84SEmmanuel Vadot } 6125d21a84SEmmanuel Vadot 6225d21a84SEmmanuel Vadot static void 6325d21a84SEmmanuel Vadot lkpi_sysuninit_i2c(void *arg __unused) 6425d21a84SEmmanuel Vadot { 6525d21a84SEmmanuel Vadot 6625d21a84SEmmanuel Vadot sx_destroy(&lkpi_sx_i2c); 6725d21a84SEmmanuel Vadot } 6825d21a84SEmmanuel Vadot 6925d21a84SEmmanuel Vadot SYSINIT(lkpi_i2c, SI_SUB_DRIVERS, SI_ORDER_ANY, 7025d21a84SEmmanuel Vadot lkpi_sysinit_i2c, NULL); 7125d21a84SEmmanuel Vadot SYSUNINIT(lkpi_i2c, SI_SUB_DRIVERS, SI_ORDER_ANY, 7225d21a84SEmmanuel Vadot lkpi_sysuninit_i2c, NULL); 7325d21a84SEmmanuel Vadot 741961a14aSEmmanuel Vadot static int 751961a14aSEmmanuel Vadot lkpi_iic_probe(device_t dev) 761961a14aSEmmanuel Vadot { 771961a14aSEmmanuel Vadot 781961a14aSEmmanuel Vadot device_set_desc(dev, "LinuxKPI I2C"); 791961a14aSEmmanuel Vadot return (BUS_PROBE_NOWILDCARD); 801961a14aSEmmanuel Vadot } 811961a14aSEmmanuel Vadot 821961a14aSEmmanuel Vadot static int 831961a14aSEmmanuel Vadot lkpi_iic_attach(device_t dev) 841961a14aSEmmanuel Vadot { 851961a14aSEmmanuel Vadot struct lkpi_iic_softc *sc; 861961a14aSEmmanuel Vadot 871961a14aSEmmanuel Vadot sc = device_get_softc(dev); 881961a14aSEmmanuel Vadot sc->iicbus = device_add_child(dev, "iicbus", -1); 891961a14aSEmmanuel Vadot if (sc->iicbus == NULL) { 901961a14aSEmmanuel Vadot device_printf(dev, "Couldn't add iicbus child, aborting\n"); 911961a14aSEmmanuel Vadot return (ENXIO); 921961a14aSEmmanuel Vadot } 93*18250ec6SJohn Baldwin bus_attach_children(dev); 941961a14aSEmmanuel Vadot return (0); 951961a14aSEmmanuel Vadot } 961961a14aSEmmanuel Vadot 971961a14aSEmmanuel Vadot static int 981961a14aSEmmanuel Vadot lkpi_iic_detach(device_t dev) 991961a14aSEmmanuel Vadot { 1001961a14aSEmmanuel Vadot struct lkpi_iic_softc *sc; 1011961a14aSEmmanuel Vadot 1021961a14aSEmmanuel Vadot sc = device_get_softc(dev); 1031961a14aSEmmanuel Vadot if (sc->iicbus) 1041961a14aSEmmanuel Vadot device_delete_child(dev, sc->iicbus); 1051961a14aSEmmanuel Vadot return (0); 1061961a14aSEmmanuel Vadot } 1071961a14aSEmmanuel Vadot 1081961a14aSEmmanuel Vadot static int 1091961a14aSEmmanuel Vadot lkpi_iic_add_adapter(device_t dev, struct i2c_adapter *adapter) 1101961a14aSEmmanuel Vadot { 1111961a14aSEmmanuel Vadot struct lkpi_iic_softc *sc; 1121961a14aSEmmanuel Vadot 1131961a14aSEmmanuel Vadot sc = device_get_softc(dev); 1141961a14aSEmmanuel Vadot sc->adapter = adapter; 1151961a14aSEmmanuel Vadot 1161961a14aSEmmanuel Vadot return (0); 1171961a14aSEmmanuel Vadot } 1181961a14aSEmmanuel Vadot 11925d21a84SEmmanuel Vadot static struct i2c_adapter * 12025d21a84SEmmanuel Vadot lkpi_iic_get_adapter(device_t dev) 12125d21a84SEmmanuel Vadot { 12225d21a84SEmmanuel Vadot struct lkpi_iic_softc *sc; 12325d21a84SEmmanuel Vadot 12425d21a84SEmmanuel Vadot sc = device_get_softc(dev); 12525d21a84SEmmanuel Vadot return (sc->adapter); 12625d21a84SEmmanuel Vadot } 12725d21a84SEmmanuel Vadot 1281961a14aSEmmanuel Vadot static device_method_t lkpi_iic_methods[] = { 1291961a14aSEmmanuel Vadot /* device interface */ 1301961a14aSEmmanuel Vadot DEVMETHOD(device_probe, lkpi_iic_probe), 1311961a14aSEmmanuel Vadot DEVMETHOD(device_attach, lkpi_iic_attach), 1321961a14aSEmmanuel Vadot DEVMETHOD(device_detach, lkpi_iic_detach), 1331961a14aSEmmanuel Vadot DEVMETHOD(device_suspend, bus_generic_suspend), 1341961a14aSEmmanuel Vadot DEVMETHOD(device_resume, bus_generic_resume), 1351961a14aSEmmanuel Vadot 1361961a14aSEmmanuel Vadot /* iicbus interface */ 1371961a14aSEmmanuel Vadot DEVMETHOD(iicbus_transfer, lkpi_i2c_transfer), 1381961a14aSEmmanuel Vadot DEVMETHOD(iicbus_reset, lkpi_i2c_reset), 1391961a14aSEmmanuel Vadot DEVMETHOD(iicbus_callback, iicbus_null_callback), 1401961a14aSEmmanuel Vadot 1411961a14aSEmmanuel Vadot /* lkpi_iic interface */ 1421961a14aSEmmanuel Vadot DEVMETHOD(lkpi_iic_add_adapter, lkpi_iic_add_adapter), 14325d21a84SEmmanuel Vadot DEVMETHOD(lkpi_iic_get_adapter, lkpi_iic_get_adapter), 1441961a14aSEmmanuel Vadot 1451961a14aSEmmanuel Vadot DEVMETHOD_END 1461961a14aSEmmanuel Vadot }; 1471961a14aSEmmanuel Vadot 1481961a14aSEmmanuel Vadot driver_t lkpi_iic_driver = { 1491961a14aSEmmanuel Vadot "lkpi_iic", 1501961a14aSEmmanuel Vadot lkpi_iic_methods, 1511961a14aSEmmanuel Vadot sizeof(struct lkpi_iic_softc), 1521961a14aSEmmanuel Vadot }; 1531961a14aSEmmanuel Vadot 154a65d0774SJohn Baldwin DRIVER_MODULE(lkpi_iic, drmn, lkpi_iic_driver, 0, 0); 155f49cddbdSVladimir Kondratyev DRIVER_MODULE(lkpi_iic, drm, lkpi_iic_driver, 0, 0); 156676ea8e1SJohn Baldwin DRIVER_MODULE(iicbus, lkpi_iic, iicbus_driver, 0, 0); 15781de5561SEmmanuel Vadot MODULE_DEPEND(linuxkpi, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 1581961a14aSEmmanuel Vadot 1591961a14aSEmmanuel Vadot static int 1601961a14aSEmmanuel Vadot lkpi_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 1611961a14aSEmmanuel Vadot { 1621961a14aSEmmanuel Vadot 1631961a14aSEmmanuel Vadot /* That doesn't seems to be supported in linux */ 1641961a14aSEmmanuel Vadot return (0); 1651961a14aSEmmanuel Vadot } 1661961a14aSEmmanuel Vadot 16783276e1fSJean-Sébastien Pédron static int i2c_check_for_quirks(struct i2c_adapter *adapter, 16883276e1fSJean-Sébastien Pédron struct iic_msg *msgs, uint32_t nmsgs) 16983276e1fSJean-Sébastien Pédron { 17083276e1fSJean-Sébastien Pédron const struct i2c_adapter_quirks *quirks; 17183276e1fSJean-Sébastien Pédron device_t dev; 17283276e1fSJean-Sébastien Pédron int i, max_nmsgs; 17383276e1fSJean-Sébastien Pédron bool check_len; 17483276e1fSJean-Sébastien Pédron 17583276e1fSJean-Sébastien Pédron dev = adapter->dev.parent->bsddev; 17683276e1fSJean-Sébastien Pédron quirks = adapter->quirks; 17783276e1fSJean-Sébastien Pédron if (quirks == NULL) 17883276e1fSJean-Sébastien Pédron return (0); 17983276e1fSJean-Sébastien Pédron 18083276e1fSJean-Sébastien Pédron check_len = true; 18183276e1fSJean-Sébastien Pédron max_nmsgs = quirks->max_num_msgs; 18283276e1fSJean-Sébastien Pédron 18383276e1fSJean-Sébastien Pédron if (quirks->flags & I2C_AQ_COMB) { 18483276e1fSJean-Sébastien Pédron max_nmsgs = 2; 18583276e1fSJean-Sébastien Pédron 18683276e1fSJean-Sébastien Pédron if (nmsgs == 2) { 18783276e1fSJean-Sébastien Pédron if (quirks->flags & I2C_AQ_COMB_WRITE_FIRST && 18883276e1fSJean-Sébastien Pédron msgs[0].flags & IIC_M_RD) { 18983276e1fSJean-Sébastien Pédron device_printf(dev, 19083276e1fSJean-Sébastien Pédron "Error: " 19183276e1fSJean-Sébastien Pédron "first combined message must be write\n"); 19283276e1fSJean-Sébastien Pédron return (EOPNOTSUPP); 19383276e1fSJean-Sébastien Pédron } 19483276e1fSJean-Sébastien Pédron if (quirks->flags & I2C_AQ_COMB_READ_SECOND && 19583276e1fSJean-Sébastien Pédron !(msgs[1].flags & IIC_M_RD)) { 19683276e1fSJean-Sébastien Pédron device_printf(dev, 19783276e1fSJean-Sébastien Pédron "Error: " 19883276e1fSJean-Sébastien Pédron "second combined message must be read\n"); 19983276e1fSJean-Sébastien Pédron return (EOPNOTSUPP); 20083276e1fSJean-Sébastien Pédron } 20183276e1fSJean-Sébastien Pédron 20283276e1fSJean-Sébastien Pédron if (quirks->flags & I2C_AQ_COMB_SAME_ADDR && 20383276e1fSJean-Sébastien Pédron msgs[0].slave != msgs[1].slave) { 20483276e1fSJean-Sébastien Pédron device_printf(dev, 20583276e1fSJean-Sébastien Pédron "Error: " 20683276e1fSJean-Sébastien Pédron "combined message must be use the same " 20783276e1fSJean-Sébastien Pédron "address\n"); 20883276e1fSJean-Sébastien Pédron return (EOPNOTSUPP); 20983276e1fSJean-Sébastien Pédron } 21083276e1fSJean-Sébastien Pédron 21183276e1fSJean-Sébastien Pédron if (quirks->max_comb_1st_msg_len && 21283276e1fSJean-Sébastien Pédron msgs[0].len > quirks->max_comb_1st_msg_len) { 21383276e1fSJean-Sébastien Pédron device_printf(dev, 21483276e1fSJean-Sébastien Pédron "Error: " 21583276e1fSJean-Sébastien Pédron "message too long: %hu > %hu max\n", 21683276e1fSJean-Sébastien Pédron msgs[0].len, 21783276e1fSJean-Sébastien Pédron quirks->max_comb_1st_msg_len); 21883276e1fSJean-Sébastien Pédron return (EOPNOTSUPP); 21983276e1fSJean-Sébastien Pédron } 22083276e1fSJean-Sébastien Pédron if (quirks->max_comb_2nd_msg_len && 22183276e1fSJean-Sébastien Pédron msgs[1].len > quirks->max_comb_2nd_msg_len) { 22283276e1fSJean-Sébastien Pédron device_printf(dev, 22383276e1fSJean-Sébastien Pédron "Error: " 22483276e1fSJean-Sébastien Pédron "message too long: %hu > %hu max\n", 22583276e1fSJean-Sébastien Pédron msgs[1].len, 22683276e1fSJean-Sébastien Pédron quirks->max_comb_2nd_msg_len); 22783276e1fSJean-Sébastien Pédron return (EOPNOTSUPP); 22883276e1fSJean-Sébastien Pédron } 22983276e1fSJean-Sébastien Pédron 23083276e1fSJean-Sébastien Pédron check_len = false; 23183276e1fSJean-Sébastien Pédron } 23283276e1fSJean-Sébastien Pédron } 23383276e1fSJean-Sébastien Pédron 23483276e1fSJean-Sébastien Pédron if (max_nmsgs && nmsgs > max_nmsgs) { 23583276e1fSJean-Sébastien Pédron device_printf(dev, 23683276e1fSJean-Sébastien Pédron "Error: too many messages: %d > %d max\n", 23783276e1fSJean-Sébastien Pédron nmsgs, max_nmsgs); 23883276e1fSJean-Sébastien Pédron return (EOPNOTSUPP); 23983276e1fSJean-Sébastien Pédron } 24083276e1fSJean-Sébastien Pédron 24183276e1fSJean-Sébastien Pédron for (i = 0; i < nmsgs; i++) { 24283276e1fSJean-Sébastien Pédron if (msgs[i].flags & IIC_M_RD) { 24383276e1fSJean-Sébastien Pédron if (check_len && quirks->max_read_len && 24483276e1fSJean-Sébastien Pédron msgs[i].len > quirks->max_read_len) { 24583276e1fSJean-Sébastien Pédron device_printf(dev, 24683276e1fSJean-Sébastien Pédron "Error: " 24783276e1fSJean-Sébastien Pédron "message %d too long: %hu > %hu max\n", 24883276e1fSJean-Sébastien Pédron i, msgs[i].len, quirks->max_read_len); 24983276e1fSJean-Sébastien Pédron return (EOPNOTSUPP); 25083276e1fSJean-Sébastien Pédron } 25183276e1fSJean-Sébastien Pédron if (quirks->flags & I2C_AQ_NO_ZERO_LEN_READ && 25283276e1fSJean-Sébastien Pédron msgs[i].len == 0) { 25383276e1fSJean-Sébastien Pédron device_printf(dev, 25483276e1fSJean-Sébastien Pédron "Error: message %d of length 0\n", i); 25583276e1fSJean-Sébastien Pédron return (EOPNOTSUPP); 25683276e1fSJean-Sébastien Pédron } 25783276e1fSJean-Sébastien Pédron } else { 25883276e1fSJean-Sébastien Pédron if (check_len && quirks->max_write_len && 25983276e1fSJean-Sébastien Pédron msgs[i].len > quirks->max_write_len) { 26083276e1fSJean-Sébastien Pédron device_printf(dev, 26183276e1fSJean-Sébastien Pédron "Message %d too long: %hu > %hu max\n", 26283276e1fSJean-Sébastien Pédron i, msgs[i].len, quirks->max_write_len); 26383276e1fSJean-Sébastien Pédron return (EOPNOTSUPP); 26483276e1fSJean-Sébastien Pédron } 26583276e1fSJean-Sébastien Pédron if (quirks->flags & I2C_AQ_NO_ZERO_LEN_WRITE && 26683276e1fSJean-Sébastien Pédron msgs[i].len == 0) { 26783276e1fSJean-Sébastien Pédron device_printf(dev, 26883276e1fSJean-Sébastien Pédron "Error: message %d of length 0\n", i); 26983276e1fSJean-Sébastien Pédron return (EOPNOTSUPP); 27083276e1fSJean-Sébastien Pédron } 27183276e1fSJean-Sébastien Pédron } 27283276e1fSJean-Sébastien Pédron } 27383276e1fSJean-Sébastien Pédron 27483276e1fSJean-Sébastien Pédron return (0); 27583276e1fSJean-Sébastien Pédron } 27683276e1fSJean-Sébastien Pédron 2771961a14aSEmmanuel Vadot static int 2781961a14aSEmmanuel Vadot lkpi_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs) 2791961a14aSEmmanuel Vadot { 2801961a14aSEmmanuel Vadot struct lkpi_iic_softc *sc; 2811961a14aSEmmanuel Vadot struct i2c_msg *linux_msgs; 2821961a14aSEmmanuel Vadot int i, ret = 0; 2831961a14aSEmmanuel Vadot 2841961a14aSEmmanuel Vadot sc = device_get_softc(dev); 2851961a14aSEmmanuel Vadot if (sc->adapter == NULL) 2861961a14aSEmmanuel Vadot return (ENXIO); 28783276e1fSJean-Sébastien Pédron ret = i2c_check_for_quirks(sc->adapter, msgs, nmsgs); 28883276e1fSJean-Sébastien Pédron if (ret != 0) 28983276e1fSJean-Sébastien Pédron return (ret); 2901961a14aSEmmanuel Vadot linux_set_current(curthread); 2911961a14aSEmmanuel Vadot 2921961a14aSEmmanuel Vadot linux_msgs = malloc(sizeof(struct i2c_msg) * nmsgs, 2931961a14aSEmmanuel Vadot M_DEVBUF, M_WAITOK | M_ZERO); 2941961a14aSEmmanuel Vadot 2951961a14aSEmmanuel Vadot for (i = 0; i < nmsgs; i++) { 296319a4bddSEmmanuel Vadot linux_msgs[i].addr = msgs[i].slave >> 1; 2971961a14aSEmmanuel Vadot linux_msgs[i].len = msgs[i].len; 2981961a14aSEmmanuel Vadot linux_msgs[i].buf = msgs[i].buf; 2991961a14aSEmmanuel Vadot if (msgs[i].flags & IIC_M_RD) { 3001961a14aSEmmanuel Vadot linux_msgs[i].flags |= I2C_M_RD; 3011961a14aSEmmanuel Vadot for (int j = 0; j < msgs[i].len; j++) 3021961a14aSEmmanuel Vadot msgs[i].buf[j] = 0; 3031961a14aSEmmanuel Vadot } 3041961a14aSEmmanuel Vadot if (msgs[i].flags & IIC_M_NOSTART) 3051961a14aSEmmanuel Vadot linux_msgs[i].flags |= I2C_M_NOSTART; 3061961a14aSEmmanuel Vadot } 3071961a14aSEmmanuel Vadot ret = i2c_transfer(sc->adapter, linux_msgs, nmsgs); 3081961a14aSEmmanuel Vadot free(linux_msgs, M_DEVBUF); 3091961a14aSEmmanuel Vadot 3101961a14aSEmmanuel Vadot if (ret < 0) 3111961a14aSEmmanuel Vadot return (-ret); 3121961a14aSEmmanuel Vadot return (0); 3131961a14aSEmmanuel Vadot } 3141961a14aSEmmanuel Vadot 3151961a14aSEmmanuel Vadot int 3161961a14aSEmmanuel Vadot lkpi_i2c_add_adapter(struct i2c_adapter *adapter) 3171961a14aSEmmanuel Vadot { 3181961a14aSEmmanuel Vadot device_t lkpi_iic; 3191961a14aSEmmanuel Vadot 32025d21a84SEmmanuel Vadot if (adapter->name[0] == '\0') 32125d21a84SEmmanuel Vadot return (-EINVAL); 3221961a14aSEmmanuel Vadot if (bootverbose) 3231961a14aSEmmanuel Vadot device_printf(adapter->dev.parent->bsddev, 3241961a14aSEmmanuel Vadot "Adding i2c adapter %s\n", adapter->name); 32525d21a84SEmmanuel Vadot sx_xlock(&lkpi_sx_i2c); 3261961a14aSEmmanuel Vadot lkpi_iic = device_add_child(adapter->dev.parent->bsddev, "lkpi_iic", -1); 3271961a14aSEmmanuel Vadot if (lkpi_iic == NULL) { 3281961a14aSEmmanuel Vadot device_printf(adapter->dev.parent->bsddev, "Couldn't add lkpi_iic\n"); 32925d21a84SEmmanuel Vadot sx_xunlock(&lkpi_sx_i2c); 3301961a14aSEmmanuel Vadot return (ENXIO); 3311961a14aSEmmanuel Vadot } 3321961a14aSEmmanuel Vadot 333d87fad36SEmmanuel Vadot bus_topo_lock(); 334*18250ec6SJohn Baldwin bus_attach_children(adapter->dev.parent->bsddev); 335d87fad36SEmmanuel Vadot bus_topo_unlock(); 3361961a14aSEmmanuel Vadot LKPI_IIC_ADD_ADAPTER(lkpi_iic, adapter); 33725d21a84SEmmanuel Vadot sx_xunlock(&lkpi_sx_i2c); 3381961a14aSEmmanuel Vadot return (0); 3391961a14aSEmmanuel Vadot } 3401961a14aSEmmanuel Vadot 3411961a14aSEmmanuel Vadot int 3421961a14aSEmmanuel Vadot lkpi_i2c_del_adapter(struct i2c_adapter *adapter) 3431961a14aSEmmanuel Vadot { 3441961a14aSEmmanuel Vadot device_t child; 34525d21a84SEmmanuel Vadot int unit, rv; 3461961a14aSEmmanuel Vadot 34725d21a84SEmmanuel Vadot if (adapter == NULL) 34825d21a84SEmmanuel Vadot return (-EINVAL); 3491961a14aSEmmanuel Vadot if (bootverbose) 3501961a14aSEmmanuel Vadot device_printf(adapter->dev.parent->bsddev, 3511961a14aSEmmanuel Vadot "Removing i2c adapter %s\n", adapter->name); 35225d21a84SEmmanuel Vadot sx_xlock(&lkpi_sx_i2c); 35325d21a84SEmmanuel Vadot unit = 0; 35425d21a84SEmmanuel Vadot while ((child = device_find_child(adapter->dev.parent->bsddev, "lkpi_iic", unit++)) != NULL) { 3551961a14aSEmmanuel Vadot 35625d21a84SEmmanuel Vadot if (adapter == LKPI_IIC_GET_ADAPTER(child)) { 357d87fad36SEmmanuel Vadot bus_topo_lock(); 3581961a14aSEmmanuel Vadot device_delete_child(adapter->dev.parent->bsddev, child); 359d87fad36SEmmanuel Vadot bus_topo_unlock(); 36025d21a84SEmmanuel Vadot rv = 0; 36125d21a84SEmmanuel Vadot goto out; 36225d21a84SEmmanuel Vadot } 36325d21a84SEmmanuel Vadot } 3641961a14aSEmmanuel Vadot 36525d21a84SEmmanuel Vadot unit = 0; 36625d21a84SEmmanuel Vadot while ((child = device_find_child(adapter->dev.parent->bsddev, "lkpi_iicbb", unit++)) != NULL) { 36725d21a84SEmmanuel Vadot 36825d21a84SEmmanuel Vadot if (adapter == LKPI_IIC_GET_ADAPTER(child)) { 369d87fad36SEmmanuel Vadot bus_topo_lock(); 3701961a14aSEmmanuel Vadot device_delete_child(adapter->dev.parent->bsddev, child); 371d87fad36SEmmanuel Vadot bus_topo_unlock(); 37225d21a84SEmmanuel Vadot rv = 0; 37325d21a84SEmmanuel Vadot goto out; 37425d21a84SEmmanuel Vadot } 37525d21a84SEmmanuel Vadot } 37625d21a84SEmmanuel Vadot rv = -EINVAL; 37725d21a84SEmmanuel Vadot out: 37825d21a84SEmmanuel Vadot sx_xunlock(&lkpi_sx_i2c); 37925d21a84SEmmanuel Vadot return (rv); 3801961a14aSEmmanuel Vadot } 381