git: c0525ab1d1ce - main - pca954x: driver for PCA954x / TCA954x I2C switches
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sat, 13 Nov 2021 09:28:19 UTC
The branch main has been updated by avg:
URL: https://cgit.FreeBSD.org/src/commit/?id=c0525ab1d1ce69ab3d589e95733caedb04e0dcbd
commit c0525ab1d1ce69ab3d589e95733caedb04e0dcbd
Author: Andriy Gapon <avg@FreeBSD.org>
AuthorDate: 2020-08-18 09:16:28 +0000
Commit: Andriy Gapon <avg@FreeBSD.org>
CommitDate: 2021-11-13 09:27:41 +0000
pca954x: driver for PCA954x / TCA954x I2C switches
At the moment only PCA9548A is supported and has been tested.
MFC after: 2 weeks
---
share/man/man4/Makefile | 1 +
share/man/man4/pca954x.4 | 119 +++++++++++++++++++
sys/conf/files | 1 +
sys/dev/iicbus/mux/pca954x.c | 214 +++++++++++++++++++++++++++++++++++
sys/modules/i2c/mux/Makefile | 1 +
sys/modules/i2c/mux/pca954x/Makefile | 20 ++++
6 files changed, 356 insertions(+)
diff --git a/share/man/man4/Makefile b/share/man/man4/Makefile
index d3cd58b495f4..dfef254bff56 100644
--- a/share/man/man4/Makefile
+++ b/share/man/man4/Makefile
@@ -418,6 +418,7 @@ MAN= aac.4 \
owc.4 \
${_padlock.4} \
pass.4 \
+ pca954x.4 \
pccard.4 \
pccbb.4 \
pcf.4 \
diff --git a/share/man/man4/pca954x.4 b/share/man/man4/pca954x.4
new file mode 100644
index 000000000000..d845740f9b6c
--- /dev/null
+++ b/share/man/man4/pca954x.4
@@ -0,0 +1,119 @@
+.\"
+.\" SPDX-License-Identifier: BSD-2-Clause-FreeBSD
+.\"
+.\" Copyright (c) 2020 Andriy Gapon <avg@FreeBSD.org>
+.\"
+.\" 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.
+.\"
+.\" $FreeBSD$
+.\"
+.Dd November 13, 2021
+.Dt PCA954X 4
+.Os
+.Sh NAME
+.Nm pca954x
+.Nd driver for PCA9548A I2C switch
+.Sh SYNOPSIS
+To compile this driver into the kernel,
+place the following line in your
+kernel configuration file:
+.Bd -ragged -offset indent
+.Cd "device pca954x"
+.Cd "device iicmux"
+.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
+pca954x_load="YES"
+.Ed
+.Sh DESCRIPTION
+The
+.Nm
+driver supports the PCA9548A I2C bus switch and compatible chips such as
+TCA9548A.
+It automatically connects an upstream I2C bus to one of several downstream
+buses as needed when slave devices on the downstream buses initiate I/O.
+More information on the automatic switching behavior is available in
+.Xr iicmux 4 .
+.Sh FDT CONFIGURATION
+On an
+.Xr FDT 4
+based system, an
+.Nm
+device node is defined as a child node of its upstream I2C bus.
+The children of the
+.Nm
+node are additional I2C buses, which will have their own I2C slave
+devices described in their child nodes.
+.Pp
+The
+.Nm
+driver attaches to nodes where the
+.Va compatible
+property is set to one of
+.Bl -bullet
+.It
+.Qq nxp,pca9548
+.El
+.Pp
+The
+.Nm
+driver supports the following optional properties in addition to the standard
+I2C mux properties:
+.Bl -tag -width i2c-mux-idle-disconnect
+.It Va i2c-mux-idle-disconnect
+if defined, forces the switch to disconnect all children in idle state.
+.El
+.Sh HINTS CONFIGURATION
+On a
+.Xr device.hints 5
+based system, these values are configurable for
+.Nm :
+.Bl -tag -width hint.pca954x.<unit>.chip_type
+.It Va hint.pca954x.<unit>.at
+The upstream
+.Xr iicbus 4
+the
+.Nm
+instance is attached to.
+.It Va hint.pca954x.<unit>.chip_type
+The type of the chip.
+At present, only
+.Qq pca9548
+is supported.
+.El
+.Pp
+When configured via hints, the driver automatically adds an
+.Xr iicbus 4
+instance for every downstream bus supported by the chip.
+There is currently no way to indicate used versus unused channels.
+.Sh SEE ALSO
+.Xr iicbus 4 ,
+.Xr iicmux 4
+.Sh HISTORY
+The
+.Nm
+driver and this manual page was written by
+.An Andriy Gapon Aq Mt avg@FreeBSD.org .
diff --git a/sys/conf/files b/sys/conf/files
index 30f98817e290..4cc6e3dcde8c 100644
--- a/sys/conf/files
+++ b/sys/conf/files
@@ -1855,6 +1855,7 @@ dev/iicbus/mux/iicmux.c optional iicmux
dev/iicbus/mux/iicmux_if.m optional iicmux
dev/iicbus/mux/iic_gpiomux.c optional iic_gpiomux fdt
dev/iicbus/mux/ltc430x.c optional ltc430x
+dev/iicbus/mux/pca954x.c optional pca954x
dev/iicbus/nxprtc.c optional nxprtc | pcf8563
dev/iicbus/ofw_iicbus.c optional fdt iicbus
dev/iicbus/pcf8574.c optional pcf8574
diff --git a/sys/dev/iicbus/mux/pca954x.c b/sys/dev/iicbus/mux/pca954x.c
new file mode 100644
index 000000000000..44c81539691e
--- /dev/null
+++ b/sys/dev/iicbus/mux/pca954x.c
@@ -0,0 +1,214 @@
+/*-
+ * SPDX-License-Identifier: BSD-2-Clause
+ *
+ * Copyright (c) Andriy Gapon
+ *
+ * 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 "opt_platform.h"
+
+#include <sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+
+#ifdef FDT
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/ofw/openfirm.h>
+#endif
+
+#include <dev/iicbus/iicbus.h>
+#include <dev/iicbus/iiconf.h>
+#include "iicbus_if.h"
+#include "iicmux_if.h"
+#include <dev/iicbus/mux/iicmux.h>
+
+struct pca954x_descr {
+ const char *partname;
+ const char *description;
+ int numchannels;
+};
+
+static struct pca954x_descr pca9548_descr = {
+ .partname = "pca9548",
+ .description = "PCA9548A I2C Mux",
+ .numchannels = 8,
+};
+
+#ifdef FDT
+static struct ofw_compat_data compat_data[] = {
+ { "nxp,pca9548", (uintptr_t)&pca9548_descr },
+ { NULL, 0 },
+};
+#else
+static struct pca954x_descr *part_descrs[] = {
+ &pca9548_descr,
+};
+#endif
+
+struct pca954x_softc {
+ struct iicmux_softc mux;
+ uint8_t addr;
+ bool idle_disconnect;
+};
+
+static int
+pca954x_bus_select(device_t dev, int busidx, struct iic_reqbus_data *rd)
+{
+ struct iic_msg msg;
+ struct pca954x_softc *sc = device_get_softc(dev);
+ uint8_t busbits;
+ int error;
+
+ /*
+ * The iicmux caller ensures busidx is between 0 and the number of buses
+ * we passed to iicmux_init_softc(), no need for validation here. If
+ * the fdt data has the idle_disconnect property we idle the bus by
+ * selecting no downstream buses, otherwise we just leave the current
+ * bus active.
+ */
+ if (busidx == IICMUX_SELECT_IDLE) {
+ if (sc->idle_disconnect)
+ busbits = 0;
+ else
+ return (0);
+ } else {
+ busbits = 1u << busidx;
+ }
+
+ msg.slave = sc->addr;
+ msg.flags = IIC_M_WR;
+ msg.len = 1;
+ msg.buf = &busbits;
+ error = iicbus_transfer(dev, &msg, 1);
+ return (error);
+}
+
+static const struct pca954x_descr *
+pca954x_find_chip(device_t dev)
+{
+#ifdef FDT
+ const struct ofw_compat_data *compat;
+
+ compat = ofw_bus_search_compatible(dev, compat_data);
+ if (compat == NULL)
+ return (NULL);
+ return ((const struct pca954x_descr *)compat->ocd_data);
+#else
+ const char *type;
+ int i;
+
+ if (resource_string_value(device_get_name(dev), device_get_unit(dev),
+ "chip_type", &type) == 0) {
+ for (i = 0; i < nitems(part_descrs) - 1; ++i) {
+ if (strcasecmp(type, part_descrs[i]->partname) == 0)
+ return (part_descrs[i]);
+ }
+ }
+ return (NULL);
+#endif
+}
+
+static int
+pca954x_probe(device_t dev)
+{
+ const struct pca954x_descr *descr;
+
+ descr = pca954x_find_chip(dev);
+ if (descr == NULL)
+ return (ENXIO);
+
+ device_set_desc(dev, descr->description);
+ return (BUS_PROBE_DEFAULT);
+}
+
+static int
+pca954x_attach(device_t dev)
+{
+#ifdef FDT
+ phandle_t node;
+#endif
+ struct pca954x_softc *sc;
+ const struct pca954x_descr *descr;
+ int err;
+
+ sc = device_get_softc(dev);
+ sc->addr = iicbus_get_addr(dev);
+#ifdef FDT
+ node = ofw_bus_get_node(dev);
+ sc->idle_disconnect = OF_hasprop(node, "i2c-mux-idle-disconnect");
+#endif
+
+ descr = pca954x_find_chip(dev);
+ err = iicmux_attach(dev, device_get_parent(dev), descr->numchannels);
+ if (err == 0)
+ bus_generic_attach(dev);
+ return (err);
+}
+
+static int
+pca954x_detach(device_t dev)
+{
+ int err;
+
+ err = iicmux_detach(dev);
+ return (err);
+}
+
+static device_method_t pca954x_methods[] = {
+ /* device methods */
+ DEVMETHOD(device_probe, pca954x_probe),
+ DEVMETHOD(device_attach, pca954x_attach),
+ DEVMETHOD(device_detach, pca954x_detach),
+
+ /* iicmux methods */
+ DEVMETHOD(iicmux_bus_select, pca954x_bus_select),
+
+ DEVMETHOD_END
+};
+
+static devclass_t pca954x_devclass;
+
+DEFINE_CLASS_1(pca9548, pca954x_driver, pca954x_methods,
+ sizeof(struct pca954x_softc), iicmux_driver);
+DRIVER_MODULE(pca9548, iicbus, pca954x_driver, pca954x_devclass, 0, 0);
+
+#ifdef FDT
+DRIVER_MODULE(ofw_iicbus, pca9548, ofw_iicbus_driver, ofw_iicbus_devclass, 0, 0);
+#else
+DRIVER_MODULE(iicbus, pca9548, iicbus_driver, iicbus_devclass, 0, 0);
+#endif
+
+MODULE_DEPEND(pca9548, iicmux, 1, 1, 1);
+MODULE_DEPEND(pca9548, iicbus, IICBUS_MINVER, IICBUS_PREFVER, IICBUS_MAXVER);
+MODULE_VERSION(pca9548, 1);
+
+#ifdef FDT
+IICBUS_FDT_PNP_INFO(compat_data);
+#endif
diff --git a/sys/modules/i2c/mux/Makefile b/sys/modules/i2c/mux/Makefile
index 8e228a7a7fef..a972a00a3b3a 100644
--- a/sys/modules/i2c/mux/Makefile
+++ b/sys/modules/i2c/mux/Makefile
@@ -3,6 +3,7 @@
SUBDIR = \
iicmux \
ltc430x \
+ pca954x \
.if !empty(OPT_FDT)
SUBDIR+= iic_gpiomux
diff --git a/sys/modules/i2c/mux/pca954x/Makefile b/sys/modules/i2c/mux/pca954x/Makefile
new file mode 100644
index 000000000000..622b327204c5
--- /dev/null
+++ b/sys/modules/i2c/mux/pca954x/Makefile
@@ -0,0 +1,20 @@
+# $FreeBSD$
+
+.PATH: ${SRCTOP}/sys/dev/iicbus/mux
+
+KMOD= pca954x
+SRCS= pca954x.c
+
+SRCS+= \
+ bus_if.h \
+ device_if.h \
+ iicbus_if.h \
+ iicmux_if.h \
+ opt_platform.h \
+
+.if !empty(OPT_FDT)
+SRCS+= ofw_bus_if.h
+.endif
+
+
+.include <bsd.kmod.mk>