The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/compat/linuxkpi/common/src/linux_i2c.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
    3  *
    4  * Redistribution and use in source and binary forms, with or without
    5  * modification, are permitted provided that the following conditions
    6  * are met:
    7  * 1. Redistributions of source code must retain the above copyright
    8  *    notice, this list of conditions and the following disclaimer.
    9  * 2. Redistributions in binary form must reproduce the above copyright
   10  *    notice, this list of conditions and the following disclaimer in the
   11  *    documentation and/or other materials provided with the distribution.
   12  *
   13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   23  * SUCH DAMAGE.
   24  *
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/malloc.h>
   34 
   35 #include <dev/iicbus/iicbus.h>
   36 #include <dev/iicbus/iiconf.h>
   37 
   38 #include <linux/device.h>
   39 #include <linux/i2c.h>
   40 #include <linux/i2c-algo-bit.h>
   41 #include <linux/list.h>
   42 #include <linux/pci.h>
   43 
   44 #include "iicbus_if.h"
   45 #include "iicbb_if.h"
   46 #include "lkpi_iic_if.h"
   47 
   48 static int lkpi_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs);
   49 static int lkpi_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr);
   50 
   51 struct lkpi_iic_softc {
   52         device_t                iicbus;
   53         struct i2c_adapter      *adapter;
   54 };
   55 
   56 static struct sx lkpi_sx_i2c;
   57 
   58 static void
   59 lkpi_sysinit_i2c(void *arg __unused)
   60 {
   61 
   62         sx_init(&lkpi_sx_i2c, "lkpi-i2c");
   63 }
   64 
   65 static void
   66 lkpi_sysuninit_i2c(void *arg __unused)
   67 {
   68 
   69         sx_destroy(&lkpi_sx_i2c);
   70 }
   71 
   72 SYSINIT(lkpi_i2c, SI_SUB_DRIVERS, SI_ORDER_ANY,
   73     lkpi_sysinit_i2c, NULL);
   74 SYSUNINIT(lkpi_i2c, SI_SUB_DRIVERS, SI_ORDER_ANY,
   75     lkpi_sysuninit_i2c, NULL);
   76 
   77 static int
   78 lkpi_iic_probe(device_t dev)
   79 {
   80 
   81         device_set_desc(dev, "LinuxKPI I2C");
   82         return (BUS_PROBE_NOWILDCARD);
   83 }
   84 
   85 static int
   86 lkpi_iic_attach(device_t dev)
   87 {
   88         struct lkpi_iic_softc *sc;
   89 
   90         sc = device_get_softc(dev);
   91         sc->iicbus = device_add_child(dev, "iicbus", -1);
   92         if (sc->iicbus == NULL) {
   93                 device_printf(dev, "Couldn't add iicbus child, aborting\n");
   94                 return (ENXIO);
   95         }
   96         bus_generic_attach(dev);
   97         return (0);
   98 }
   99 
  100 static int
  101 lkpi_iic_detach(device_t dev)
  102 {
  103         struct lkpi_iic_softc *sc;
  104 
  105         sc = device_get_softc(dev);
  106         if (sc->iicbus)
  107                 device_delete_child(dev, sc->iicbus);
  108         return (0);
  109 }
  110 
  111 static int
  112 lkpi_iic_add_adapter(device_t dev, struct i2c_adapter *adapter)
  113 {
  114         struct lkpi_iic_softc *sc;
  115 
  116         sc = device_get_softc(dev);
  117         sc->adapter = adapter;
  118 
  119         return (0);
  120 }
  121 
  122 static struct i2c_adapter *
  123 lkpi_iic_get_adapter(device_t dev)
  124 {
  125         struct lkpi_iic_softc *sc;
  126 
  127         sc = device_get_softc(dev);
  128         return (sc->adapter);
  129 }
  130 
  131 static device_method_t lkpi_iic_methods[] = {
  132         /* device interface */
  133         DEVMETHOD(device_probe,         lkpi_iic_probe),
  134         DEVMETHOD(device_attach,        lkpi_iic_attach),
  135         DEVMETHOD(device_detach,        lkpi_iic_detach),
  136         DEVMETHOD(device_suspend,       bus_generic_suspend),
  137         DEVMETHOD(device_resume,        bus_generic_resume),
  138 
  139         /* iicbus interface */
  140         DEVMETHOD(iicbus_transfer,      lkpi_i2c_transfer),
  141         DEVMETHOD(iicbus_reset,         lkpi_i2c_reset),
  142         DEVMETHOD(iicbus_callback,      iicbus_null_callback),
  143 
  144         /* lkpi_iic interface */
  145         DEVMETHOD(lkpi_iic_add_adapter, lkpi_iic_add_adapter),
  146         DEVMETHOD(lkpi_iic_get_adapter, lkpi_iic_get_adapter),
  147 
  148         DEVMETHOD_END
  149 };
  150 
  151 driver_t lkpi_iic_driver = {
  152         "lkpi_iic",
  153         lkpi_iic_methods,
  154         sizeof(struct lkpi_iic_softc),
  155 };
  156 
  157 DRIVER_MODULE(lkpi_iic, drmn, lkpi_iic_driver, 0, 0);
  158 DRIVER_MODULE(lkpi_iic, drm, lkpi_iic_driver, 0, 0);
  159 DRIVER_MODULE(iicbus, lkpi_iic, iicbus_driver, 0, 0);
  160 MODULE_DEPEND(linuxkpi, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
  161 
  162 static int
  163 lkpi_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
  164 {
  165 
  166         /* That doesn't seems to be supported in linux */
  167         return (0);
  168 }
  169 
  170 static int
  171 lkpi_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
  172 {
  173         struct lkpi_iic_softc *sc;
  174         struct i2c_msg *linux_msgs;
  175         int i, ret = 0;
  176 
  177         sc = device_get_softc(dev);
  178         if (sc->adapter == NULL)
  179                 return (ENXIO);
  180         linux_set_current(curthread);
  181 
  182         linux_msgs = malloc(sizeof(struct i2c_msg) * nmsgs,
  183             M_DEVBUF, M_WAITOK | M_ZERO);
  184 
  185         for (i = 0; i < nmsgs; i++) {
  186                 linux_msgs[i].addr = msgs[i].slave >> 1;
  187                 linux_msgs[i].len = msgs[i].len;
  188                 linux_msgs[i].buf = msgs[i].buf;
  189                 if (msgs[i].flags & IIC_M_RD) {
  190                         linux_msgs[i].flags |= I2C_M_RD;
  191                         for (int j = 0; j < msgs[i].len; j++)
  192                                 msgs[i].buf[j] = 0;
  193                 }
  194                 if (msgs[i].flags & IIC_M_NOSTART)
  195                         linux_msgs[i].flags |= I2C_M_NOSTART;
  196         }
  197         ret = i2c_transfer(sc->adapter, linux_msgs, nmsgs);
  198         free(linux_msgs, M_DEVBUF);
  199 
  200         if (ret < 0)
  201                 return (-ret);
  202         return (0);
  203 }
  204 
  205 int
  206 lkpi_i2c_add_adapter(struct i2c_adapter *adapter)
  207 {
  208         device_t lkpi_iic;
  209         int error;
  210 
  211         if (adapter->name[0] == '\0')
  212                 return (-EINVAL);
  213         if (bootverbose)
  214                 device_printf(adapter->dev.parent->bsddev,
  215                     "Adding i2c adapter %s\n", adapter->name);
  216         sx_xlock(&lkpi_sx_i2c);
  217         lkpi_iic = device_add_child(adapter->dev.parent->bsddev, "lkpi_iic", -1);
  218         if (lkpi_iic == NULL) {
  219                 device_printf(adapter->dev.parent->bsddev, "Couldn't add lkpi_iic\n");
  220                 sx_xunlock(&lkpi_sx_i2c);
  221                 return (ENXIO);
  222         }
  223 
  224         bus_topo_lock();
  225         error = bus_generic_attach(adapter->dev.parent->bsddev);
  226         bus_topo_unlock();
  227         if (error) {
  228                 device_printf(adapter->dev.parent->bsddev,
  229                   "failed to attach child: error %d\n", error);
  230                 sx_xunlock(&lkpi_sx_i2c);
  231                 return (ENXIO);
  232         }
  233         LKPI_IIC_ADD_ADAPTER(lkpi_iic, adapter);
  234         sx_xunlock(&lkpi_sx_i2c);
  235         return (0);
  236 }
  237 
  238 int
  239 lkpi_i2c_del_adapter(struct i2c_adapter *adapter)
  240 {
  241         device_t child;
  242         int unit, rv;
  243 
  244         if (adapter == NULL)
  245                 return (-EINVAL);
  246         if (bootverbose)
  247                 device_printf(adapter->dev.parent->bsddev,
  248                     "Removing i2c adapter %s\n", adapter->name);
  249         sx_xlock(&lkpi_sx_i2c);
  250         unit = 0;
  251         while ((child = device_find_child(adapter->dev.parent->bsddev, "lkpi_iic", unit++)) != NULL) {
  252 
  253                 if (adapter == LKPI_IIC_GET_ADAPTER(child)) {
  254                         bus_topo_lock();
  255                         device_delete_child(adapter->dev.parent->bsddev, child);
  256                         bus_topo_unlock();
  257                         rv = 0;
  258                         goto out;
  259                 }
  260         }
  261 
  262         unit = 0;
  263         while ((child = device_find_child(adapter->dev.parent->bsddev, "lkpi_iicbb", unit++)) != NULL) {
  264 
  265                 if (adapter == LKPI_IIC_GET_ADAPTER(child)) {
  266                         bus_topo_lock();
  267                         device_delete_child(adapter->dev.parent->bsddev, child);
  268                         bus_topo_unlock();
  269                         rv = 0;
  270                         goto out;
  271                 }
  272         }
  273         rv = -EINVAL;
  274 out:
  275         sx_xunlock(&lkpi_sx_i2c);
  276         return (rv);
  277 }

Cache object: 23cf4c63306f50403fb4d5a53321a26c


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.