pca954x: driver for PCA954x / TCA954x I2C switches
At the moment only PCA9548A is supported and has been tested. MFC after: 2 weeks
This commit is contained in:
parent
01e3492337
commit
c0525ab1d1
@ -418,6 +418,7 @@ MAN= aac.4 \
|
||||
owc.4 \
|
||||
${_padlock.4} \
|
||||
pass.4 \
|
||||
pca954x.4 \
|
||||
pccard.4 \
|
||||
pccbb.4 \
|
||||
pcf.4 \
|
||||
|
119
share/man/man4/pca954x.4
Normal file
119
share/man/man4/pca954x.4
Normal file
@ -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 .
|
@ -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
|
||||
|
214
sys/dev/iicbus/mux/pca954x.c
Normal file
214
sys/dev/iicbus/mux/pca954x.c
Normal file
@ -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
|
@ -3,6 +3,7 @@
|
||||
SUBDIR = \
|
||||
iicmux \
|
||||
ltc430x \
|
||||
pca954x \
|
||||
|
||||
.if !empty(OPT_FDT)
|
||||
SUBDIR+= iic_gpiomux
|
||||
|
20
sys/modules/i2c/mux/pca954x/Makefile
Normal file
20
sys/modules/i2c/mux/pca954x/Makefile
Normal file
@ -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>
|
Loading…
Reference in New Issue
Block a user