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>