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 4163641805SEmmanuel Vadot #include "iicbus_if.h" 421961a14aSEmmanuel Vadot #include "iicbb_if.h" 431961a14aSEmmanuel Vadot #include "lkpi_iic_if.h" 441961a14aSEmmanuel Vadot 451961a14aSEmmanuel Vadot static void lkpi_iicbb_setsda(device_t dev, int val); 461961a14aSEmmanuel Vadot static void lkpi_iicbb_setscl(device_t dev, int val); 471961a14aSEmmanuel Vadot static int lkpi_iicbb_getscl(device_t dev); 481961a14aSEmmanuel Vadot static int lkpi_iicbb_getsda(device_t dev); 491961a14aSEmmanuel Vadot static int lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr); 5063641805SEmmanuel Vadot static int lkpi_iicbb_pre_xfer(device_t dev); 5163641805SEmmanuel Vadot static void lkpi_iicbb_post_xfer(device_t dev); 521961a14aSEmmanuel Vadot 531961a14aSEmmanuel Vadot struct lkpi_iicbb_softc { 541961a14aSEmmanuel Vadot device_t iicbb; 551961a14aSEmmanuel Vadot struct i2c_adapter *adapter; 561961a14aSEmmanuel Vadot }; 571961a14aSEmmanuel Vadot 5863641805SEmmanuel Vadot static struct sx lkpi_sx_i2cbb; 5963641805SEmmanuel Vadot 6063641805SEmmanuel Vadot static void 6163641805SEmmanuel Vadot lkpi_sysinit_i2cbb(void *arg __unused) 6263641805SEmmanuel Vadot { 6363641805SEmmanuel Vadot 6463641805SEmmanuel Vadot sx_init(&lkpi_sx_i2cbb, "lkpi-i2cbb"); 6563641805SEmmanuel Vadot } 6663641805SEmmanuel Vadot 6763641805SEmmanuel Vadot static void 6863641805SEmmanuel Vadot lkpi_sysuninit_i2cbb(void *arg __unused) 6963641805SEmmanuel Vadot { 7063641805SEmmanuel Vadot 7163641805SEmmanuel Vadot sx_destroy(&lkpi_sx_i2cbb); 7263641805SEmmanuel Vadot } 7363641805SEmmanuel Vadot 7463641805SEmmanuel Vadot SYSINIT(lkpi_i2cbb, SI_SUB_DRIVERS, SI_ORDER_ANY, 7563641805SEmmanuel Vadot lkpi_sysinit_i2cbb, NULL); 7663641805SEmmanuel Vadot SYSUNINIT(lkpi_i2cbb, SI_SUB_DRIVERS, SI_ORDER_ANY, 7763641805SEmmanuel Vadot lkpi_sysuninit_i2cbb, NULL); 7863641805SEmmanuel Vadot 791961a14aSEmmanuel Vadot static int 801961a14aSEmmanuel Vadot lkpi_iicbb_probe(device_t dev) 811961a14aSEmmanuel Vadot { 821961a14aSEmmanuel Vadot 831961a14aSEmmanuel Vadot device_set_desc(dev, "LinuxKPI I2CBB"); 841961a14aSEmmanuel Vadot return (BUS_PROBE_NOWILDCARD); 851961a14aSEmmanuel Vadot } 861961a14aSEmmanuel Vadot 871961a14aSEmmanuel Vadot static int 881961a14aSEmmanuel Vadot lkpi_iicbb_attach(device_t dev) 891961a14aSEmmanuel Vadot { 901961a14aSEmmanuel Vadot struct lkpi_iicbb_softc *sc; 911961a14aSEmmanuel Vadot 921961a14aSEmmanuel Vadot sc = device_get_softc(dev); 931961a14aSEmmanuel Vadot sc->iicbb = device_add_child(dev, "iicbb", -1); 941961a14aSEmmanuel Vadot if (sc->iicbb == NULL) { 951961a14aSEmmanuel Vadot device_printf(dev, "Couldn't add iicbb child, aborting\n"); 961961a14aSEmmanuel Vadot return (ENXIO); 971961a14aSEmmanuel Vadot } 98*18250ec6SJohn Baldwin bus_attach_children(dev); 991961a14aSEmmanuel Vadot return (0); 1001961a14aSEmmanuel Vadot } 1011961a14aSEmmanuel Vadot 1021961a14aSEmmanuel Vadot static int 1031961a14aSEmmanuel Vadot lkpi_iicbb_detach(device_t dev) 1041961a14aSEmmanuel Vadot { 1051961a14aSEmmanuel Vadot struct lkpi_iicbb_softc *sc; 1061961a14aSEmmanuel Vadot 1071961a14aSEmmanuel Vadot sc = device_get_softc(dev); 1081961a14aSEmmanuel Vadot if (sc->iicbb) 1091961a14aSEmmanuel Vadot device_delete_child(dev, sc->iicbb); 1101961a14aSEmmanuel Vadot return (0); 1111961a14aSEmmanuel Vadot } 1121961a14aSEmmanuel Vadot 1131961a14aSEmmanuel Vadot static int 1141961a14aSEmmanuel Vadot lkpi_iicbb_add_adapter(device_t dev, struct i2c_adapter *adapter) 1151961a14aSEmmanuel Vadot { 1161961a14aSEmmanuel Vadot struct lkpi_iicbb_softc *sc; 11763641805SEmmanuel Vadot struct i2c_algo_bit_data *algo_data; 1181961a14aSEmmanuel Vadot 1191961a14aSEmmanuel Vadot sc = device_get_softc(dev); 1201961a14aSEmmanuel Vadot sc->adapter = adapter; 1211961a14aSEmmanuel Vadot 12263641805SEmmanuel Vadot /* 12363641805SEmmanuel Vadot * Set iicbb timing parameters deriving speed from the protocol delay. 12463641805SEmmanuel Vadot */ 12563641805SEmmanuel Vadot algo_data = adapter->algo_data; 12663641805SEmmanuel Vadot if (algo_data->udelay != 0) 12763641805SEmmanuel Vadot IICBUS_RESET(sc->iicbb, 1000000 / algo_data->udelay, 0, NULL); 1281961a14aSEmmanuel Vadot return (0); 1291961a14aSEmmanuel Vadot } 1301961a14aSEmmanuel Vadot 13125d21a84SEmmanuel Vadot static struct i2c_adapter * 13225d21a84SEmmanuel Vadot lkpi_iicbb_get_adapter(device_t dev) 13325d21a84SEmmanuel Vadot { 13425d21a84SEmmanuel Vadot struct lkpi_iicbb_softc *sc; 13525d21a84SEmmanuel Vadot 13625d21a84SEmmanuel Vadot sc = device_get_softc(dev); 13725d21a84SEmmanuel Vadot return (sc->adapter); 13825d21a84SEmmanuel Vadot } 13925d21a84SEmmanuel Vadot 1401961a14aSEmmanuel Vadot static device_method_t lkpi_iicbb_methods[] = { 1411961a14aSEmmanuel Vadot /* device interface */ 1421961a14aSEmmanuel Vadot DEVMETHOD(device_probe, lkpi_iicbb_probe), 1431961a14aSEmmanuel Vadot DEVMETHOD(device_attach, lkpi_iicbb_attach), 1441961a14aSEmmanuel Vadot DEVMETHOD(device_detach, lkpi_iicbb_detach), 1451961a14aSEmmanuel Vadot DEVMETHOD(device_suspend, bus_generic_suspend), 1461961a14aSEmmanuel Vadot DEVMETHOD(device_resume, bus_generic_resume), 1471961a14aSEmmanuel Vadot 1481961a14aSEmmanuel Vadot /* iicbb interface */ 1491961a14aSEmmanuel Vadot DEVMETHOD(iicbb_setsda, lkpi_iicbb_setsda), 1501961a14aSEmmanuel Vadot DEVMETHOD(iicbb_setscl, lkpi_iicbb_setscl), 1511961a14aSEmmanuel Vadot DEVMETHOD(iicbb_getsda, lkpi_iicbb_getsda), 1521961a14aSEmmanuel Vadot DEVMETHOD(iicbb_getscl, lkpi_iicbb_getscl), 1531961a14aSEmmanuel Vadot DEVMETHOD(iicbb_reset, lkpi_iicbb_reset), 15463641805SEmmanuel Vadot DEVMETHOD(iicbb_pre_xfer, lkpi_iicbb_pre_xfer), 15563641805SEmmanuel Vadot DEVMETHOD(iicbb_post_xfer, lkpi_iicbb_post_xfer), 1561961a14aSEmmanuel Vadot 1571961a14aSEmmanuel Vadot /* lkpi_iicbb interface */ 1581961a14aSEmmanuel Vadot DEVMETHOD(lkpi_iic_add_adapter, lkpi_iicbb_add_adapter), 15925d21a84SEmmanuel Vadot DEVMETHOD(lkpi_iic_get_adapter, lkpi_iicbb_get_adapter), 1601961a14aSEmmanuel Vadot 1611961a14aSEmmanuel Vadot DEVMETHOD_END 1621961a14aSEmmanuel Vadot }; 1631961a14aSEmmanuel Vadot 1641961a14aSEmmanuel Vadot driver_t lkpi_iicbb_driver = { 1651961a14aSEmmanuel Vadot "lkpi_iicbb", 1661961a14aSEmmanuel Vadot lkpi_iicbb_methods, 1671961a14aSEmmanuel Vadot sizeof(struct lkpi_iicbb_softc), 1681961a14aSEmmanuel Vadot }; 1691961a14aSEmmanuel Vadot 17063641805SEmmanuel Vadot DRIVER_MODULE(lkpi_iicbb, drmn, lkpi_iicbb_driver, 0, 0); 17163641805SEmmanuel Vadot DRIVER_MODULE(lkpi_iicbb, drm, lkpi_iicbb_driver, 0, 0); 1728c13dd83SJohn Baldwin DRIVER_MODULE(iicbb, lkpi_iicbb, iicbb_driver, 0, 0); 17363641805SEmmanuel Vadot MODULE_DEPEND(linuxkpi, iicbb, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER); 1741961a14aSEmmanuel Vadot 1751961a14aSEmmanuel Vadot static void 1761961a14aSEmmanuel Vadot lkpi_iicbb_setsda(device_t dev, int val) 1771961a14aSEmmanuel Vadot { 1781961a14aSEmmanuel Vadot struct lkpi_iicbb_softc *sc; 1791961a14aSEmmanuel Vadot struct i2c_algo_bit_data *algo_data; 1801961a14aSEmmanuel Vadot 1811961a14aSEmmanuel Vadot sc = device_get_softc(dev); 18263641805SEmmanuel Vadot algo_data = sc->adapter->algo_data; 1831961a14aSEmmanuel Vadot algo_data->setsda(algo_data->data, val); 1841961a14aSEmmanuel Vadot } 1851961a14aSEmmanuel Vadot 1861961a14aSEmmanuel Vadot static void 1871961a14aSEmmanuel Vadot lkpi_iicbb_setscl(device_t dev, int val) 1881961a14aSEmmanuel Vadot { 1891961a14aSEmmanuel Vadot struct lkpi_iicbb_softc *sc; 1901961a14aSEmmanuel Vadot struct i2c_algo_bit_data *algo_data; 1911961a14aSEmmanuel Vadot 1921961a14aSEmmanuel Vadot sc = device_get_softc(dev); 19363641805SEmmanuel Vadot algo_data = sc->adapter->algo_data; 1941961a14aSEmmanuel Vadot algo_data->setscl(algo_data->data, val); 1951961a14aSEmmanuel Vadot } 1961961a14aSEmmanuel Vadot 1971961a14aSEmmanuel Vadot static int 1981961a14aSEmmanuel Vadot lkpi_iicbb_getscl(device_t dev) 1991961a14aSEmmanuel Vadot { 2001961a14aSEmmanuel Vadot struct lkpi_iicbb_softc *sc; 2011961a14aSEmmanuel Vadot struct i2c_algo_bit_data *algo_data; 20263641805SEmmanuel Vadot int ret; 2031961a14aSEmmanuel Vadot 2041961a14aSEmmanuel Vadot sc = device_get_softc(dev); 20563641805SEmmanuel Vadot algo_data = sc->adapter->algo_data; 2061961a14aSEmmanuel Vadot ret = algo_data->getscl(algo_data->data); 2071961a14aSEmmanuel Vadot return (ret); 2081961a14aSEmmanuel Vadot } 2091961a14aSEmmanuel Vadot 2101961a14aSEmmanuel Vadot static int 2111961a14aSEmmanuel Vadot lkpi_iicbb_getsda(device_t dev) 2121961a14aSEmmanuel Vadot { 2131961a14aSEmmanuel Vadot struct lkpi_iicbb_softc *sc; 2141961a14aSEmmanuel Vadot struct i2c_algo_bit_data *algo_data; 21563641805SEmmanuel Vadot int ret; 2161961a14aSEmmanuel Vadot 2171961a14aSEmmanuel Vadot sc = device_get_softc(dev); 21863641805SEmmanuel Vadot algo_data = sc->adapter->algo_data; 2191961a14aSEmmanuel Vadot ret = algo_data->getsda(algo_data->data); 2201961a14aSEmmanuel Vadot return (ret); 2211961a14aSEmmanuel Vadot } 2221961a14aSEmmanuel Vadot 2231961a14aSEmmanuel Vadot static int 2241961a14aSEmmanuel Vadot lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) 2251961a14aSEmmanuel Vadot { 2261961a14aSEmmanuel Vadot 22763641805SEmmanuel Vadot /* That doesn't seems to be supported in linux */ 2281961a14aSEmmanuel Vadot return (0); 2291961a14aSEmmanuel Vadot } 2301961a14aSEmmanuel Vadot 23163641805SEmmanuel Vadot static int 23263641805SEmmanuel Vadot lkpi_iicbb_pre_xfer(device_t dev) 2331961a14aSEmmanuel Vadot { 23463641805SEmmanuel Vadot struct lkpi_iicbb_softc *sc; 23563641805SEmmanuel Vadot struct i2c_algo_bit_data *algo_data; 23663641805SEmmanuel Vadot int rc = 0; 2371961a14aSEmmanuel Vadot 23863641805SEmmanuel Vadot sc = device_get_softc(dev); 23963641805SEmmanuel Vadot algo_data = sc->adapter->algo_data; 24063641805SEmmanuel Vadot if (algo_data->pre_xfer != 0) 24163641805SEmmanuel Vadot rc = algo_data->pre_xfer(sc->adapter); 24263641805SEmmanuel Vadot return (rc); 24363641805SEmmanuel Vadot } 24463641805SEmmanuel Vadot 24563641805SEmmanuel Vadot static void 24663641805SEmmanuel Vadot lkpi_iicbb_post_xfer(device_t dev) 24763641805SEmmanuel Vadot { 24863641805SEmmanuel Vadot struct lkpi_iicbb_softc *sc; 24963641805SEmmanuel Vadot struct i2c_algo_bit_data *algo_data; 25063641805SEmmanuel Vadot 25163641805SEmmanuel Vadot sc = device_get_softc(dev); 25263641805SEmmanuel Vadot algo_data = sc->adapter->algo_data; 25363641805SEmmanuel Vadot if (algo_data->post_xfer != NULL) 25463641805SEmmanuel Vadot algo_data->post_xfer(sc->adapter); 25563641805SEmmanuel Vadot } 25663641805SEmmanuel Vadot 25763641805SEmmanuel Vadot int 25863641805SEmmanuel Vadot lkpi_i2cbb_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, 25963641805SEmmanuel Vadot int nmsgs) 26063641805SEmmanuel Vadot { 26163641805SEmmanuel Vadot struct iic_msg *bsd_msgs; 26263641805SEmmanuel Vadot int ret = ENXIO; 26363641805SEmmanuel Vadot 26463641805SEmmanuel Vadot linux_set_current(curthread); 26563641805SEmmanuel Vadot 26663641805SEmmanuel Vadot bsd_msgs = malloc(sizeof(struct iic_msg) * nmsgs, 26763641805SEmmanuel Vadot M_DEVBUF, M_WAITOK | M_ZERO); 26863641805SEmmanuel Vadot 26963641805SEmmanuel Vadot for (int i = 0; i < nmsgs; i++) { 27063641805SEmmanuel Vadot bsd_msgs[i].slave = msgs[i].addr << 1; 27163641805SEmmanuel Vadot bsd_msgs[i].len = msgs[i].len; 27263641805SEmmanuel Vadot bsd_msgs[i].buf = msgs[i].buf; 27363641805SEmmanuel Vadot if (msgs[i].flags & I2C_M_RD) 27463641805SEmmanuel Vadot bsd_msgs[i].flags |= IIC_M_RD; 27563641805SEmmanuel Vadot if (msgs[i].flags & I2C_M_NOSTART) 27663641805SEmmanuel Vadot bsd_msgs[i].flags |= IIC_M_NOSTART; 27763641805SEmmanuel Vadot } 27863641805SEmmanuel Vadot 27963641805SEmmanuel Vadot for (int unit = 0; ; unit++) { 28063641805SEmmanuel Vadot device_t child; 28163641805SEmmanuel Vadot struct lkpi_iicbb_softc *sc; 28263641805SEmmanuel Vadot 28363641805SEmmanuel Vadot child = device_find_child(adapter->dev.parent->bsddev, 28463641805SEmmanuel Vadot "lkpi_iicbb", unit); 28563641805SEmmanuel Vadot if (child == NULL) 28663641805SEmmanuel Vadot break; 28763641805SEmmanuel Vadot if (adapter == LKPI_IIC_GET_ADAPTER(child)) { 28863641805SEmmanuel Vadot sc = device_get_softc(child); 28963641805SEmmanuel Vadot ret = IICBUS_TRANSFER(sc->iicbb, bsd_msgs, nmsgs); 29063641805SEmmanuel Vadot ret = iic2errno(ret); 29163641805SEmmanuel Vadot break; 29263641805SEmmanuel Vadot } 29363641805SEmmanuel Vadot } 29463641805SEmmanuel Vadot 29563641805SEmmanuel Vadot free(bsd_msgs, M_DEVBUF); 29663641805SEmmanuel Vadot 29763641805SEmmanuel Vadot if (ret != 0) 29863641805SEmmanuel Vadot return (-ret); 29963641805SEmmanuel Vadot return (nmsgs); 3001961a14aSEmmanuel Vadot } 3011961a14aSEmmanuel Vadot 3021961a14aSEmmanuel Vadot int 3031961a14aSEmmanuel Vadot lkpi_i2c_bit_add_bus(struct i2c_adapter *adapter) 3041961a14aSEmmanuel Vadot { 3051961a14aSEmmanuel Vadot device_t lkpi_iicbb; 3061961a14aSEmmanuel Vadot 3071961a14aSEmmanuel Vadot if (bootverbose) 3081961a14aSEmmanuel Vadot device_printf(adapter->dev.parent->bsddev, 3091961a14aSEmmanuel Vadot "Adding i2c adapter %s\n", adapter->name); 31063641805SEmmanuel Vadot sx_xlock(&lkpi_sx_i2cbb); 3111961a14aSEmmanuel Vadot lkpi_iicbb = device_add_child(adapter->dev.parent->bsddev, "lkpi_iicbb", -1); 3121961a14aSEmmanuel Vadot if (lkpi_iicbb == NULL) { 3131961a14aSEmmanuel Vadot device_printf(adapter->dev.parent->bsddev, "Couldn't add lkpi_iicbb\n"); 31463641805SEmmanuel Vadot sx_xunlock(&lkpi_sx_i2cbb); 3151961a14aSEmmanuel Vadot return (ENXIO); 3161961a14aSEmmanuel Vadot } 3171961a14aSEmmanuel Vadot 31863641805SEmmanuel Vadot bus_topo_lock(); 319*18250ec6SJohn Baldwin bus_attach_children(adapter->dev.parent->bsddev); 32063641805SEmmanuel Vadot bus_topo_unlock(); 3211961a14aSEmmanuel Vadot LKPI_IIC_ADD_ADAPTER(lkpi_iicbb, adapter); 32263641805SEmmanuel Vadot sx_xunlock(&lkpi_sx_i2cbb); 3231961a14aSEmmanuel Vadot return (0); 3241961a14aSEmmanuel Vadot } 325