git: 54e231b373ef - main - Add support for i2c-tiny-usb: usb to iic bridge
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Fri, 19 Apr 2024 22:48:55 UTC
The branch main has been updated by imp:
URL: https://cgit.FreeBSD.org/src/commit/?id=54e231b373ef617c348706c6c64a2e049ea738ec
commit 54e231b373ef617c348706c6c64a2e049ea738ec
Author: Denis Bodor <lefinnois@lefinnois.net>
AuthorDate: 2024-04-19 22:38:37 +0000
Commit: Warner Losh <imp@FreeBSD.org>
CommitDate: 2024-04-19 22:40:23 +0000
Add support for i2c-tiny-usb: usb to iic bridge
Reviewed by: imp
Pull Request: https://github.com/freebsd/freebsd-src/pull/1123
---
share/man/man4/Makefile | 1 +
share/man/man4/i2ctinyusb.4 | 85 ++++++++++
sys/conf/files | 1 +
sys/dev/usb/misc/i2ctinyusb.c | 302 ++++++++++++++++++++++++++++++++++++
sys/modules/usb/Makefile | 1 +
sys/modules/usb/i2ctinyusb/Makefile | 35 +++++
6 files changed, 425 insertions(+)
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index b668cccf50ae..020b009893d5 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -207,6 +207,7 @@ MAN= aac.4 \
${_hv_vss.4} \
hwpmc.4 \
${_hwpstate_intel.4} \
+ i2ctinyusb.4 \
iavf.4 \
ichsmb.4 \
${_ichwd.4} \
diff --git a/share/man/man4/i2ctinyusb.4 b/share/man/man4/i2ctinyusb.4
new file mode 100644
index 000000000000..78169a0506ff
--- /dev/null
+++ b/share/man/man4/i2ctinyusb.4
@@ -0,0 +1,85 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause
+.\"
+.\" Copyright (c) 2024 Denis Bodor <dbodor@rollmops.ninja>
+.\"
+.\" 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.
+.\"
+.Dd February 18, 2024
+.Dt I2CTINYUSB 4
+.Os
+.Sh NAME
+.Nm i2ctinyusb
+.Nd driver for a USB / I2C bridge device
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following lines in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device i2ctinyusb"
+.Cd "device usb"
+.Cd "device iicbus"
+.Ed
+.Pp
+Alternatively, to load the driver as a
+module at boot time, place the following line in
+.Xr loader.conf 5 :
+.Bd -literal -offset indent
+i2ctinyusb_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the device designed by Till Harbaum known
+as i2c-tiny-usb. This is initially a very simple circuit built with
+an Atmel AVR ATtiny45, but a Raspberry Pi Pico (RP2040) implementation
+also exists.
+.Pp
+The
+.Nm
+driver creates a
+.Xr iicbus 4
+child bus to expose the iic functions, enabling I2C sensors, converters
+and displays to be connected to any computer with a USB port.
+.Pp
+More information about this device can be found at:
+.Bd -literal -offset indent
+https://github.com/harbaum/I2C-Tiny-USB
+.Ed
+.Pp
+and (for the Raspberry Pi Pico version):
+.Bd -literal -offset indent
+https://github.com/Nicolai-Electronics/rp2040-i2c-interface
+.Ed
+.Pp
+The I2C controller supports read and write transactions with up to 1024
+bytes of data, and a write followed by the repeated start followed by a
+read transactions up to 1024 bytes.
+Zero length transfers are not supported.
+.Sh SEE ALSO
+.Xr iicbus 4 ,
+.Xr usb 4
+.Sh HISTORY
+The
+.Nm
+driver and this manual page was written by
+.An Denis Bodor Aq Mt dbodor@rollmops.ninja .
diff --git a/sys/conf/files b/sys/conf/files
index 941fa6a5a48b..27ef78e51001 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -3355,6 +3355,7 @@ dev/usb/misc/cp2112.c optional cp2112
dev/usb/misc/udbp.c optional udbp
dev/usb/misc/ugold.c optional ugold
dev/usb/misc/uled.c optional uled
+dev/usb/misc/i2ctinyusb.c optional i2ctinyusb
#
# USB input drivers
#
diff --git a/sys/dev/usb/misc/i2ctinyusb.c b/sys/dev/usb/misc/i2ctinyusb.c
new file mode 100644
index 000000000000..cae20880e441
--- /dev/null
+++ b/sys/dev/usb/misc/i2ctinyusb.c
@@ -0,0 +1,302 @@
+/*-
+ * Copyright (c) 2024 Denis Bodor <dbodor@rollmops.ninja>
+ * All rights reserved.
+ *
+ * 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 ``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 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.
+ */
+
+/*
+ * i2c-tiny-usb, DIY USB to IIC bridge (using AVR or RP2040) from
+ * Till Harbaum & Nicolai Electronics
+ * See :
+ * https://github.com/harbaum/I2C-Tiny-USB
+ * and
+ * https://github.com/Nicolai-Electronics/rp2040-i2c-interface
+ */
+
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/bus.h>
+#include <sys/module.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/unistd.h>
+#include <dev/usb/usb.h>
+#include <dev/usb/usbdi.h>
+#include <dev/usb/usbhid.h>
+#include <dev/usb/usb_device.h>
+
+#include <dev/iicbus/iiconf.h>
+#include <dev/iicbus/iicbus.h>
+#include "iicbus_if.h"
+
+// commands via USB, must match command ids in the firmware
+#define CMD_ECHO 0
+#define CMD_GET_FUNC 1
+#define CMD_SET_DELAY 2
+#define CMD_GET_STATUS 3
+#define CMD_I2C_IO 4
+#define CMD_SET_LED 8
+#define CMD_I2C_IO_BEGIN (1 << 0)
+#define CMD_I2C_IO_END (1 << 1)
+#define STATUS_IDLE 0
+#define STATUS_ADDRESS_ACK 1
+#define STATUS_ADDRESS_NAK 2
+
+struct i2ctinyusb_softc {
+ struct usb_device *sc_udev;
+ device_t sc_iic_dev;
+ device_t iicbus_dev;
+ struct mtx sc_mtx;
+};
+
+#define USB_VENDOR_EZPROTOTYPES 0x1c40
+#define USB_VENDOR_FTDI 0x0403
+
+static const STRUCT_USB_HOST_ID i2ctinyusb_devs[] = {
+ { USB_VPI(USB_VENDOR_EZPROTOTYPES, 0x0534, 0) },
+ { USB_VPI(USB_VENDOR_FTDI, 0xc631, 0) },
+};
+
+/* Prototypes. */
+static int i2ctinyusb_probe(device_t dev);
+static int i2ctinyusb_attach(device_t dev);
+static int i2ctinyusb_detach(device_t dev);
+static int i2ctinyusb_transfer(device_t dev, struct iic_msg *msgs,
+ uint32_t nmsgs);
+static int i2ctinyusb_reset(device_t dev, u_char speed, u_char addr,
+ u_char *oldaddr);
+
+static int
+usb_read(struct i2ctinyusb_softc *sc, int cmd, int value, int index,
+ void *data, int len)
+{
+ int error;
+ struct usb_device_request req;
+ uint16_t actlen;
+
+ req.bmRequestType = UT_READ_VENDOR_INTERFACE;
+ req.bRequest = cmd;
+ USETW(req.wValue, value);
+ USETW(req.wIndex, (index >> 1));
+ USETW(req.wLength, len);
+
+ error = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, data, 0,
+ &actlen, 2000);
+
+ if (error)
+ actlen = -1;
+
+ return (actlen);
+}
+
+static int
+usb_write(struct i2ctinyusb_softc *sc, int cmd, int value, int index,
+ void *data, int len)
+{
+ int error;
+ struct usb_device_request req;
+ uint16_t actlen;
+
+ req.bmRequestType = UT_WRITE_VENDOR_INTERFACE;
+ req.bRequest = cmd;
+ USETW(req.wValue, value);
+ USETW(req.wIndex, (index >> 1));
+ USETW(req.wLength, len);
+
+ error = usbd_do_request_flags(sc->sc_udev, &sc->sc_mtx, &req, data, 0,
+ &actlen, 2000);
+
+ if (error) {
+ actlen = -1;
+ }
+
+ return (actlen);
+}
+
+static int
+i2ctinyusb_probe(device_t dev)
+{
+ struct usb_attach_arg *uaa;
+
+ uaa = device_get_ivars(dev);
+
+ if (uaa->usb_mode != USB_MODE_HOST)
+ return (ENXIO);
+
+ if (usbd_lookup_id_by_uaa(i2ctinyusb_devs, sizeof(i2ctinyusb_devs),
+ uaa) == 0) {
+ device_set_desc(dev, "I2C-Tiny-USB I2C interface");
+ return (BUS_PROBE_DEFAULT);
+ }
+
+ return (ENXIO);
+}
+
+static int
+i2ctinyusb_attach(device_t dev)
+{
+ struct i2ctinyusb_softc *sc;
+ struct usb_attach_arg *uaa;
+ int err;
+
+ sc = device_get_softc(dev);
+
+ uaa = device_get_ivars(dev);
+ device_set_usb_desc(dev);
+
+ sc->sc_udev = uaa->device;
+ mtx_init(&sc->sc_mtx, "i2ctinyusb lock", NULL, MTX_DEF | MTX_RECURSE);
+
+ sc->iicbus_dev = device_add_child(dev, "iicbus", -1);
+ if (sc->iicbus_dev == NULL) {
+ device_printf(dev, "iicbus creation failed\n");
+ err = ENXIO;
+ goto detach;
+ }
+ err = bus_generic_attach(dev);
+
+ return (0);
+
+detach:
+ i2ctinyusb_detach(dev);
+ return (err);
+}
+
+static int
+i2ctinyusb_detach(device_t dev)
+{
+ struct i2ctinyusb_softc *sc;
+ int err;
+
+ sc = device_get_softc(dev);
+
+ err = bus_generic_detach(dev);
+ if (err != 0)
+ return (err);
+ device_delete_children(dev);
+
+ mtx_destroy(&sc->sc_mtx);
+
+ return (0);
+}
+
+static int
+i2ctinyusb_transfer(device_t dev, struct iic_msg *msgs, uint32_t nmsgs)
+{
+ struct i2ctinyusb_softc *sc;
+ uint32_t i;
+ int ret = 0;
+ int cmd = CMD_I2C_IO;
+ struct iic_msg *pmsg;
+ unsigned char pstatus;
+
+ sc = device_get_softc(dev);
+
+ mtx_lock(&sc->sc_mtx);
+
+ for (i = 0; i < nmsgs; i++) {
+ pmsg = &msgs[i];
+ if (i == 0)
+ cmd |= CMD_I2C_IO_BEGIN;
+ if (i == nmsgs - 1)
+ cmd |= CMD_I2C_IO_END;
+
+ if ((msgs[i].flags & IIC_M_RD) != 0) {
+ if ((ret = usb_read(sc, cmd, pmsg->flags, pmsg->slave, pmsg->buf,
+ pmsg->len)) != pmsg->len) {
+ printf("Read error: got %u\n", ret);
+ ret = EIO;
+ goto out;
+ }
+ } else {
+ if ((ret = usb_write(sc, cmd, pmsg->flags, pmsg->slave, pmsg->buf,
+ pmsg->len)) != pmsg->len) {
+ printf("Write error: got %u\n", ret);
+ ret = EIO;
+ goto out;
+ }
+
+ }
+ // check status
+ if ((ret = usb_read(sc, CMD_GET_STATUS, 0, 0, &pstatus, 1)) != 1) {
+ ret = EIO;
+ goto out;
+ }
+
+ if (pstatus == STATUS_ADDRESS_NAK) {
+ ret = EIO;
+ goto out;
+ }
+ }
+
+ ret = 0;
+
+out:
+ mtx_unlock(&sc->sc_mtx);
+ return (ret);
+}
+
+static int
+i2ctinyusb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr)
+{
+ struct i2ctinyusb_softc *sc;
+ int ret;
+
+ sc = device_get_softc(dev);
+
+ mtx_lock(&sc->sc_mtx);
+ ret = usb_write(sc, CMD_SET_DELAY, 10, 0, NULL, 0);
+ mtx_unlock(&sc->sc_mtx);
+
+ if (ret < 0)
+ printf("i2ctinyusb_reset error!\n");
+
+ return (0);
+}
+
+static device_method_t i2ctinyusb_methods[] = {
+ /* Device interface */
+ DEVMETHOD(device_probe, i2ctinyusb_probe),
+ DEVMETHOD(device_attach, i2ctinyusb_attach),
+ DEVMETHOD(device_detach, i2ctinyusb_detach),
+
+ /* I2C methods */
+ DEVMETHOD(iicbus_transfer, i2ctinyusb_transfer),
+ DEVMETHOD(iicbus_reset, i2ctinyusb_reset),
+ DEVMETHOD(iicbus_callback, iicbus_null_callback),
+
+ DEVMETHOD_END
+};
+
+static driver_t i2ctinyusb_driver = {
+ .name = "iichb",
+ .methods = i2ctinyusb_methods,
+ .size = sizeof(struct i2ctinyusb_softc),
+};
+
+DRIVER_MODULE(i2ctinyusb, uhub, i2ctinyusb_driver, NULL, NULL);
+MODULE_DEPEND(i2ctinyusb, usb, 1, 1, 1);
+MODULE_DEPEND(i2ctinyusb, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
+MODULE_VERSION(i2ctinyusb, 1);
+
+/* vi: set ts=8 sw=8: */
diff --git a/sys/modules/usb/Makefile b/sys/modules/usb/Makefile
index 3a81c7fd44f3..2d166a95dc03 100644
--- a/sys/modules/usb/Makefile
+++ b/sys/modules/usb/Makefile
@@ -50,6 +50,7 @@ SUBDIR += atp cfumass uhid uhid_snes ukbd ums udbp uep wmt wsp ugold uled \
usbhid
SUBDIR += ucom u3g uark ubsa ubser uchcom ucycom ufoma uftdi ugensa uipaq ulpt \
umct umcs umodem umoscom uplcom uslcom uvisor uvscom
+SUBDIR += i2ctinyusb
SUBDIR += cp2112
SUBDIR += udl
SUBDIR += uether aue axe axge cdce cdceem cue ${_kue} mos rue smsc udav uhso \
diff --git a/sys/modules/usb/i2ctinyusb/Makefile b/sys/modules/usb/i2ctinyusb/Makefile
new file mode 100644
index 000000000000..9cb37843935c
--- /dev/null
+++ b/sys/modules/usb/i2ctinyusb/Makefile
@@ -0,0 +1,35 @@
+#
+#
+# Copyright (c) Denis Bodor <dbodor@rollmops.ninja>
+#
+# 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.
+#
+
+S= ${SRCTOP}/sys
+
+.PATH: $S/dev/usb/misc
+
+KMOD= i2ctinyusb
+SRCS= i2ctinyusb.c
+SRCS+= i2ctinyusb.c device_if.h bus_if.h opt_usb.h usbdevs.h iicbus_if.h
+
+.include <bsd.kmod.mk>