The branch stable/13 has been updated by manu:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=7f14bc44022da73cfdb0dd6d73a4ade239c7e857

commit 7f14bc44022da73cfdb0dd6d73a4ade239c7e857
Author:     Emmanuel Vadot <[email protected]>
AuthorDate: 2021-11-04 09:42:37 +0000
Commit:     Emmanuel Vadot <[email protected]>
CommitDate: 2022-06-21 15:13:57 +0000

    linuxkpi: Add i2c support
    
    Add i2c support to linuxkpi. This is needed by drm-kmod.
    For every i2c_adapter added by i2c_add_adapter we add a child to the
    device named "lkpi_iic". This child handle the conversion between
    Linux i2c_msgs to FreeBSD iic_msgs.
    For every i2c_adapter added by i2c_bit_add_bus we add a child to the
    device named "lkpi_iicbb". This child handle the conversion between
    Linux i2c_msgs to FreeBSD iic_msgs.
    With the help of iic(4), this expose the i2c controller to userspace
    allowing a user to query DDC information from a monitor.
    e.g.: i2c -f /dev/iic0 -a 0x28 -c 128 -d r
    will query the standard EDID from the monitor if plugged.
    
    The bitbang part (lkpi_iicbb) isn't tested at all for now as I don't have
    compatible hardware (all my hardware have native i2c controller).
    
    Tested on:      Intel (SandyBridge, Skylake, ApolloLake)
    Tested on:      AMD (Picasso, Polaris (amd64 and arm64))
    
    MFC after:      1 month
    Reviewed by:    hselasky
    Sponsored by:   Beckhoff Automation GmbH & Co. KG
    Differential Revision:  https://reviews.freebsd.org/D33053
    
    (cherry picked from commit 1961a14a47437595fb7fcdc20e327440e3eb51e2)
---
 .../linuxkpi/common/include/linux/i2c-algo-bit.h   |  49 ++++
 sys/compat/linuxkpi/common/include/linux/i2c.h     | 152 +++++++++++++
 sys/compat/linuxkpi/common/src/linux_i2c.c         | 217 ++++++++++++++++++
 sys/compat/linuxkpi/common/src/linux_i2cbb.c       | 252 +++++++++++++++++++++
 sys/compat/linuxkpi/common/src/lkpi_iic_if.m       |  37 +++
 sys/conf/files                                     |  19 +-
 sys/conf/kmod.mk                                   |   4 +
 sys/modules/linuxkpi/Makefile                      |   2 +
 8 files changed, 725 insertions(+), 7 deletions(-)

diff --git a/sys/compat/linuxkpi/common/include/linux/i2c-algo-bit.h 
b/sys/compat/linuxkpi/common/include/linux/i2c-algo-bit.h
new file mode 100644
index 000000000000..4e8f00f9bebc
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/i2c-algo-bit.h
@@ -0,0 +1,49 @@
+/*-
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _LINUX_I2C_ALGO_BIT_H_
+#define        _LINUX_I2C_ALGO_BIT_H_
+
+#include <linux/i2c.h>
+
+struct i2c_algo_bit_data {
+       void *data;
+       void (*setsda) (void *data, int state);
+       void (*setscl) (void *data, int state);
+       int (*getsda) (void *data);
+       int (*getscl) (void *data);
+       int (*pre_xfer)  (struct i2c_adapter *);
+       void (*post_xfer) (struct i2c_adapter *);
+
+       int udelay;
+       int timeout;
+};
+
+int lkpi_i2c_bit_add_bus(struct i2c_adapter *adapter);
+
+#define        i2c_bit_add_bus(adapter)        lkpi_i2c_bit_add_bus(adapter)
+
+#endif /*_LINUX_I2C_ALGO_BIT_H_ */
diff --git a/sys/compat/linuxkpi/common/include/linux/i2c.h 
b/sys/compat/linuxkpi/common/include/linux/i2c.h
new file mode 100644
index 000000000000..0bb8b470edd7
--- /dev/null
+++ b/sys/compat/linuxkpi/common/include/linux/i2c.h
@@ -0,0 +1,152 @@
+/*-
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#ifndef _LINUX_I2C_H_
+#define        _LINUX_I2C_H_
+
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+
+#include <linux/device.h>
+
+#define        I2C_MAX_ADAPTER_NAME_LENGTH     32
+
+#define        I2C_M_RD        0x0001
+#define        I2C_M_NOSTART   0x0002
+#define        I2C_M_STOP      0x0004
+
+/* No need for us */
+#define        I2C_FUNC_I2C                    0
+#define        I2C_FUNC_SMBUS_EMUL             0
+#define        I2C_FUNC_SMBUS_READ_BLOCK_DATA  0
+#define        I2C_FUNC_SMBUS_BLOCK_PROC_CALL  0
+#define        I2C_FUNC_10BIT_ADDR             0
+
+#define        I2C_CLASS_DDC   0x8
+#define        I2C_CLASS_SPD   0x80
+
+struct i2c_adapter {
+       struct module *owner;
+       unsigned int class;
+
+       char name[I2C_MAX_ADAPTER_NAME_LENGTH];
+       struct device dev;
+
+       const struct i2c_lock_operations *lock_ops;
+       const struct i2c_algorithm *algo;
+       void *algo_data;
+
+       int retries;
+       void *data;
+};
+
+struct i2c_msg {
+       uint16_t addr;
+       uint16_t flags;
+       uint16_t len;
+       uint8_t *buf;
+};
+
+struct i2c_algorithm {
+       int (*master_xfer)(struct i2c_adapter *, struct i2c_msg *, int);
+       uint32_t (*functionality)(struct i2c_adapter *);
+};
+
+struct i2c_lock_operations {
+       void (*lock_bus)(struct i2c_adapter *, unsigned int);
+       int (*trylock_bus)(struct i2c_adapter *, unsigned int);
+       void (*unlock_bus)(struct i2c_adapter *, unsigned int);
+};
+
+int lkpi_i2c_add_adapter(struct i2c_adapter *adapter);
+int lkpi_i2c_del_adapter(struct i2c_adapter *adapter);
+
+int lkpi_i2cbb_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int 
nmsgs);
+
+#define        i2c_add_adapter(adapter)        lkpi_i2c_add_adapter(adapter)
+#define        i2c_del_adapter(adapter)        lkpi_i2c_del_adapter(adapter)
+
+#define        i2c_get_adapter(x)      NULL
+#define        i2c_put_adapter(x)
+
+static inline int
+do_i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs)
+{
+       int ret, retries;
+
+       retries = adapter->retries == 0 ? 1 : adapter->retries;
+       for (; retries != 0; retries--) {
+               if (adapter->algo->master_xfer != NULL)
+                       ret = adapter->algo->master_xfer(adapter, msgs, nmsgs);
+               else
+                       ret = lkpi_i2cbb_transfer(adapter, msgs, nmsgs);
+               if (ret != -EAGAIN)
+                       break;
+       }
+
+       return (ret);
+}
+
+static inline int
+i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs)
+{
+       int ret;
+
+       if (!adapter->algo)
+               return (-EOPNOTSUPP);
+
+       if (adapter->lock_ops)
+               adapter->lock_ops->lock_bus(adapter, 0);
+
+       ret = do_i2c_transfer(adapter, msgs, nmsgs);
+
+       if (adapter->lock_ops)
+               adapter->lock_ops->unlock_bus(adapter, 0);
+
+       return (ret);
+}
+
+/* Unlocked version of i2c_transfer */
+static inline int
+__i2c_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int nmsgs)
+{
+       return (do_i2c_transfer(adapter, msgs, nmsgs));
+}
+
+static inline void
+i2c_set_adapdata(struct i2c_adapter *adapter, void *data)
+{
+       adapter->data = data;
+}
+
+static inline void *
+i2c_get_adapdata(struct i2c_adapter *adapter)
+{
+       return (adapter->data);
+}
+
+#endif /* _LINUX_I2C_H_ */
diff --git a/sys/compat/linuxkpi/common/src/linux_i2c.c 
b/sys/compat/linuxkpi/common/src/linux_i2c.c
new file mode 100644
index 000000000000..cd002da49b19
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_i2c.c
@@ -0,0 +1,217 @@
+/*-
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+
+#include "iicbus_if.h"
+#include "iicbb_if.h"
+#include "lkpi_iic_if.h"
+
+static int lkpi_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t 
nmsgs);
+static int lkpi_i2c_reset(device_t dev, u_char speed, u_char addr, u_char 
*oldaddr);
+
+struct lkpi_iic_softc {
+       device_t                iicbus;
+       struct i2c_adapter      *adapter;
+};
+
+static int
+lkpi_iic_probe(device_t dev)
+{
+
+       device_set_desc(dev, "LinuxKPI I2C");
+       return (BUS_PROBE_NOWILDCARD);
+}
+
+static int
+lkpi_iic_attach(device_t dev)
+{
+       struct lkpi_iic_softc *sc;
+
+       sc = device_get_softc(dev);
+       sc->iicbus = device_add_child(dev, "iicbus", -1);
+       if (sc->iicbus == NULL) {
+               device_printf(dev, "Couldn't add iicbus child, aborting\n");
+               return (ENXIO);
+       }
+       bus_generic_attach(dev);
+       return (0);
+}
+
+static int
+lkpi_iic_detach(device_t dev)
+{
+       struct lkpi_iic_softc *sc;
+
+       sc = device_get_softc(dev);
+       if (sc->iicbus)
+               device_delete_child(dev, sc->iicbus);
+       return (0);
+}
+
+static int
+lkpi_iic_add_adapter(device_t dev, struct i2c_adapter *adapter)
+{
+       struct lkpi_iic_softc *sc;
+
+       sc = device_get_softc(dev);
+       sc->adapter = adapter;
+
+       return (0);
+}
+
+static device_method_t lkpi_iic_methods[] = {
+       /* device interface */
+       DEVMETHOD(device_probe,         lkpi_iic_probe),
+       DEVMETHOD(device_attach,        lkpi_iic_attach),
+       DEVMETHOD(device_detach,        lkpi_iic_detach),
+       DEVMETHOD(device_suspend,       bus_generic_suspend),
+       DEVMETHOD(device_resume,        bus_generic_resume),
+
+       /* iicbus interface */
+       DEVMETHOD(iicbus_transfer,      lkpi_i2c_transfer),
+       DEVMETHOD(iicbus_reset,         lkpi_i2c_reset),
+       DEVMETHOD(iicbus_callback,      iicbus_null_callback),
+
+       /* lkpi_iic interface */
+       DEVMETHOD(lkpi_iic_add_adapter, lkpi_iic_add_adapter),
+
+       DEVMETHOD_END
+};
+
+devclass_t lkpi_iic_devclass;
+
+driver_t lkpi_iic_driver = {
+       "lkpi_iic",
+       lkpi_iic_methods,
+       sizeof(struct lkpi_iic_softc),
+};
+
+DRIVER_MODULE(lkpi_iic, drmn, lkpi_iic_driver, lkpi_iic_devclass, 0, 0);
+DRIVER_MODULE(iicbus, lkpi_iic, iicbus_driver, iicbus_devclass, 0, 0);
+
+static int
+lkpi_i2c_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
+{
+
+       /* That doesn't seems to be supported in linux */
+       return (0);
+}
+
+static int
+lkpi_i2c_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
+{
+       struct lkpi_iic_softc *sc;
+       struct i2c_msg *linux_msgs;
+       int i, ret = 0;
+
+       sc = device_get_softc(dev);
+       if (sc->adapter == NULL)
+               return (ENXIO);
+       linux_set_current(curthread);
+
+       linux_msgs = malloc(sizeof(struct i2c_msg) * nmsgs,
+           M_DEVBUF, M_WAITOK | M_ZERO);
+
+       for (i = 0; i < nmsgs; i++) {
+               linux_msgs[i].addr = msgs[i].slave;
+               linux_msgs[i].len = msgs[i].len;
+               linux_msgs[i].buf = msgs[i].buf;
+               if (msgs[i].flags & IIC_M_RD) {
+                       linux_msgs[i].flags |= I2C_M_RD;
+                       for (int j = 0; j < msgs[i].len; j++)
+                               msgs[i].buf[j] = 0;
+               }
+               if (msgs[i].flags & IIC_M_NOSTART)
+                       linux_msgs[i].flags |= I2C_M_NOSTART;
+       }
+       ret = i2c_transfer(sc->adapter, linux_msgs, nmsgs);
+       free(linux_msgs, M_DEVBUF);
+
+       if (ret < 0)
+               return (-ret);
+       return (0);
+}
+
+int
+lkpi_i2c_add_adapter(struct i2c_adapter *adapter)
+{
+       device_t lkpi_iic;
+       int error;
+
+       if (bootverbose)
+               device_printf(adapter->dev.parent->bsddev,
+                   "Adding i2c adapter %s\n", adapter->name);
+       lkpi_iic = device_add_child(adapter->dev.parent->bsddev, "lkpi_iic", 
-1);
+       if (lkpi_iic == NULL) {
+               device_printf(adapter->dev.parent->bsddev, "Couldn't add 
lkpi_iic\n");
+               return (ENXIO);
+       }
+
+       error = bus_generic_attach(adapter->dev.parent->bsddev);
+       if (error) {
+               device_printf(adapter->dev.parent->bsddev,
+                 "failed to attach child: error %d\n", error);
+               return (ENXIO);
+       }
+       LKPI_IIC_ADD_ADAPTER(lkpi_iic, adapter);
+       return (0);
+}
+
+int
+lkpi_i2c_del_adapter(struct i2c_adapter *adapter)
+{
+       device_t child;
+
+       if (bootverbose)
+               device_printf(adapter->dev.parent->bsddev,
+                   "Removing i2c adapter %s\n", adapter->name);
+
+       child = device_find_child(adapter->dev.parent->bsddev, "lkpi_iic", -1);
+       if (child != NULL)
+               device_delete_child(adapter->dev.parent->bsddev, child);
+
+       child = device_find_child(adapter->dev.parent->bsddev, "lkpi_iicbb", 
-1);
+       if (child != NULL)
+               device_delete_child(adapter->dev.parent->bsddev, child);
+
+       return (0);
+}
diff --git a/sys/compat/linuxkpi/common/src/linux_i2cbb.c 
b/sys/compat/linuxkpi/common/src/linux_i2cbb.c
new file mode 100644
index 000000000000..06d9ecd6a1fa
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/linux_i2cbb.c
@@ -0,0 +1,252 @@
+/*-
+ * Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+
+#include <linux/device.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+
+#include "iicbb_if.h"
+#include "lkpi_iic_if.h"
+
+static void lkpi_iicbb_setsda(device_t dev, int val);
+static void lkpi_iicbb_setscl(device_t dev, int val);
+static int lkpi_iicbb_getscl(device_t dev);
+static int lkpi_iicbb_getsda(device_t dev);
+static int lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char 
*oldaddr);
+
+struct lkpi_iicbb_softc {
+       device_t                iicbb;
+       struct i2c_adapter      *adapter;
+};
+
+static int
+lkpi_iicbb_probe(device_t dev)
+{
+
+       device_set_desc(dev, "LinuxKPI I2CBB");
+       return (BUS_PROBE_NOWILDCARD);
+}
+
+static int
+lkpi_iicbb_attach(device_t dev)
+{
+       struct lkpi_iicbb_softc *sc;
+
+       sc = device_get_softc(dev);
+       sc->iicbb = device_add_child(dev, "iicbb", -1);
+       if (sc->iicbb == NULL) {
+               device_printf(dev, "Couldn't add iicbb child, aborting\n");
+               return (ENXIO);
+       }
+       bus_generic_attach(dev);
+       return (0);
+}
+
+static int
+lkpi_iicbb_detach(device_t dev)
+{
+       struct lkpi_iicbb_softc *sc;
+
+       sc = device_get_softc(dev);
+       if (sc->iicbb)
+               device_delete_child(dev, sc->iicbb);
+       return (0);
+}
+
+static int
+lkpi_iicbb_add_adapter(device_t dev, struct i2c_adapter *adapter)
+{
+       struct lkpi_iicbb_softc *sc;
+
+       sc = device_get_softc(dev);
+       sc->adapter = adapter;
+
+       return (0);
+}
+
+static device_method_t lkpi_iicbb_methods[] = {
+       /* device interface */
+       DEVMETHOD(device_probe,         lkpi_iicbb_probe),
+       DEVMETHOD(device_attach,        lkpi_iicbb_attach),
+       DEVMETHOD(device_detach,        lkpi_iicbb_detach),
+       DEVMETHOD(device_suspend,       bus_generic_suspend),
+       DEVMETHOD(device_resume,        bus_generic_resume),
+
+       /* iicbb interface */
+       DEVMETHOD(iicbb_setsda,         lkpi_iicbb_setsda),
+       DEVMETHOD(iicbb_setscl,         lkpi_iicbb_setscl),
+       DEVMETHOD(iicbb_getsda,         lkpi_iicbb_getsda),
+       DEVMETHOD(iicbb_getscl,         lkpi_iicbb_getscl),
+       DEVMETHOD(iicbb_reset,          lkpi_iicbb_reset),
+
+       /* lkpi_iicbb interface */
+       DEVMETHOD(lkpi_iic_add_adapter, lkpi_iicbb_add_adapter),
+
+       DEVMETHOD_END
+};
+
+static devclass_t lkpi_iicbb_devclass;
+
+driver_t lkpi_iicbb_driver = {
+       "lkpi_iicbb",
+       lkpi_iicbb_methods,
+       sizeof(struct lkpi_iicbb_softc),
+};
+
+DRIVER_MODULE(lkpi_iicbb, lkpi_iic, lkpi_iicbb_driver, lkpi_iicbb_devclass, 0, 
0);
+DRIVER_MODULE(iicbb, lkpi_iicbb, iicbb_driver, iicbb_devclass, 0, 0);
+MODULE_DEPEND(lkpi_iicbb, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER);
+
+static void
+lkpi_iicbb_setsda(device_t dev, int val)
+{
+       struct lkpi_iicbb_softc *sc;
+       struct i2c_algo_bit_data *algo_data;
+
+       sc = device_get_softc(dev);
+       algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
+       algo_data->setsda(algo_data->data, val);
+       cpu_spinwait();
+       DELAY(algo_data->udelay);
+}
+
+static void
+lkpi_iicbb_setscl(device_t dev, int val)
+{
+       struct lkpi_iicbb_softc *sc;
+       struct i2c_algo_bit_data *algo_data;
+
+       sc = device_get_softc(dev);
+
+       algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
+       algo_data->setscl(algo_data->data, val);
+       cpu_spinwait();
+       DELAY(algo_data->udelay);
+}
+
+static int
+lkpi_iicbb_getscl(device_t dev)
+{
+       struct lkpi_iicbb_softc *sc;
+       struct i2c_algo_bit_data *algo_data;
+       unsigned long orig_ticks;
+       int ret = 0;
+
+       sc = device_get_softc(dev);
+
+       algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
+
+       orig_ticks = ticks;
+       while (!ret) {
+               ret = algo_data->getscl(algo_data->data);
+
+               if (ret)
+                       break;
+
+               if (ticks > orig_ticks + algo_data->timeout)
+                       return (ETIMEDOUT);
+
+               cpu_spinwait();
+               DELAY(algo_data->udelay);
+       }
+       DELAY(algo_data->udelay);
+       return (ret);
+}
+
+static int
+lkpi_iicbb_getsda(device_t dev)
+{
+       struct lkpi_iicbb_softc *sc;
+       struct i2c_algo_bit_data *algo_data;
+       int ret = 0;
+
+       sc = device_get_softc(dev);
+       algo_data = (struct i2c_algo_bit_data *)sc->adapter->algo_data;
+
+       cpu_spinwait();
+       DELAY(algo_data->udelay);
+       ret = algo_data->getsda(algo_data->data);
+       cpu_spinwait();
+       DELAY(algo_data->udelay);
+       return (ret);
+}
+
+static int
+lkpi_iicbb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
+{
+       struct lkpi_iicbb_softc *sc;
+
+       sc = device_get_softc(dev);
+
+       return (0);
+}
+
+int
+lkpi_i2cbb_transfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, int 
nmsgs)
+{
+
+       /* TODO: convert from i2c_msg to iic_msg and call IICBUS_TRANFER */
+       return (0);
+}
+
+int
+lkpi_i2c_bit_add_bus(struct i2c_adapter *adapter)
+{
+       device_t lkpi_iicbb;
+       int error;
+
+       if (bootverbose)
+               device_printf(adapter->dev.parent->bsddev,
+                   "Adding i2c adapter %s\n", adapter->name);
+       lkpi_iicbb = device_add_child(adapter->dev.parent->bsddev, 
"lkpi_iicbb", -1);
+       if (lkpi_iicbb == NULL) {
+               device_printf(adapter->dev.parent->bsddev, "Couldn't add 
lkpi_iicbb\n");
+               return (ENXIO);
+       }
+
+       error = bus_generic_attach(adapter->dev.parent->bsddev);
+       if (error) {
+               device_printf(adapter->dev.parent->bsddev,
+                 "failed to attach child: error %d\n", error);
+               return (ENXIO);
+       }
+       LKPI_IIC_ADD_ADAPTER(lkpi_iicbb, adapter);
+       return (0);
+}
+
diff --git a/sys/compat/linuxkpi/common/src/lkpi_iic_if.m 
b/sys/compat/linuxkpi/common/src/lkpi_iic_if.m
new file mode 100644
index 000000000000..2379182c409b
--- /dev/null
+++ b/sys/compat/linuxkpi/common/src/lkpi_iic_if.m
@@ -0,0 +1,37 @@
+#-
+# SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+#
+# Copyright (c) 2021 Beckhoff Automation GmbH & Co. KG
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+#
+
+INTERFACE lkpi_iic;
+
+HEADER {
+       struct i2c_adapter;
+}
+
+METHOD int add_adapter {
+       device_t dev;
+       struct i2c_adapter *adapter;
+};
diff --git a/sys/conf/files b/sys/conf/files
index 7fc99a929947..81781ab0bc66 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1850,7 +1850,7 @@ dev/ichsmb/ichsmb_pci.c           optional ichsmb pci
 dev/ida/ida.c                  optional ida
 dev/ida/ida_disk.c             optional ida
 dev/ida/ida_pci.c              optional ida pci
-dev/iicbus/acpi_iicbus.c       optional acpi iicbus
+dev/iicbus/acpi_iicbus.c       optional acpi iicbus | acpi compat_linuxkpi
 dev/iicbus/ad7418.c            optional ad7418
 dev/iicbus/ads111x.c           optional ads111x
 dev/iicbus/ds1307.c            optional ds1307
@@ -1861,13 +1861,13 @@ dev/iicbus/htu21.c              optional htu21
 dev/iicbus/icee.c              optional icee
 dev/iicbus/if_ic.c             optional ic
 dev/iicbus/iic.c               optional iic
-dev/iicbus/iic_recover_bus.c   optional iicbus
-dev/iicbus/iicbb.c             optional iicbb
-dev/iicbus/iicbb_if.m          optional iicbb
-dev/iicbus/iicbus.c            optional iicbus
-dev/iicbus/iicbus_if.m         optional iicbus
+dev/iicbus/iic_recover_bus.c   optional iicbus | compat_linuxkpi
+dev/iicbus/iicbb.c             optional iicbb | compat_linuxkpi
+dev/iicbus/iicbb_if.m          optional iicbb | compat_linuxkpi
+dev/iicbus/iicbus.c            optional iicbus | compat_linuxkpi
+dev/iicbus/iicbus_if.m         optional iicbus | compat_linuxkpi
 dev/iicbus/iichid.c            optional iichid acpi hid iicbus
-dev/iicbus/iiconf.c            optional iicbus
+dev/iicbus/iiconf.c            optional iicbus | compat_linuxkpi
 dev/iicbus/iicsmb.c            optional iicsmb                         \
        dependency      "iicbus_if.h"
 dev/iicbus/iicoc.c             optional iicoc
@@ -4597,6 +4597,10 @@ compat/linuxkpi/common/src/linux_firmware.c      
optional compat_linuxkpi \
        compile-with "${LINUXKPI_C}"
 compat/linuxkpi/common/src/linux_hrtimer.c     optional compat_linuxkpi \
        compile-with "${LINUXKPI_C}"
+compat/linuxkpi/common/src/linux_i2c.c         optional compat_linuxkpi \
+       compile-with "${LINUXKPI_C}"
+compat/linuxkpi/common/src/linux_i2cbb.c       optional compat_linuxkpi \
+       compile-with "${LINUXKPI_C}"
 compat/linuxkpi/common/src/linux_interrupt.c   optional compat_linuxkpi \
        compile-with "${LINUXKPI_C}"
 compat/linuxkpi/common/src/linux_kthread.c     optional compat_linuxkpi \
@@ -4633,6 +4637,7 @@ compat/linuxkpi/common/src/linux_work.c           
optional compat_linuxkpi \
        compile-with "${LINUXKPI_C}"
 compat/linuxkpi/common/src/linux_xarray.c      optional compat_linuxkpi \
        compile-with "${LINUXKPI_C}"
+compat/linuxkpi/common/src/lkpi_iic_if.m       optional compat_linuxkpi
 
 compat/linuxkpi/common/src/linux_seq_file.c            optional 
compat_linuxkpi | lindebugfs \
        compile-with "${LINUXKPI_C}"
diff --git a/sys/conf/kmod.mk b/sys/conf/kmod.mk
index 629b7554f005..cc5d394bb186 100644
--- a/sys/conf/kmod.mk
+++ b/sys/conf/kmod.mk
@@ -94,6 +94,10 @@ LINUXKPI_GENSRCS+= \
        backlight_if.h \
        bus_if.h \
        device_if.h \
+       iicbus_if.h \
+       iicbb_if.h \
+       lkpi_iic_if.c \
+       lkpi_iic_if.h \
        pci_if.h \
        pci_iov_if.h \
        pcib_if.h \
diff --git a/sys/modules/linuxkpi/Makefile b/sys/modules/linuxkpi/Makefile
index f478ebbe0baf..e34bd1e954d7 100644
--- a/sys/modules/linuxkpi/Makefile
+++ b/sys/modules/linuxkpi/Makefile
@@ -11,6 +11,8 @@ SRCS= linux_compat.c \
        linux_hrtimer.c \
        linux_idr.c \
        linux_interrupt.c \
+       linux_i2c.c \
+       linux_i2cbb.c \
        linux_kmod.c \
        linux_kthread.c \
        linux_lock.c \

Reply via email to