Index: head/share/man/man4/ltc430x.4 =================================================================== --- head/share/man/man4/ltc430x.4 (revision 365273) +++ head/share/man/man4/ltc430x.4 (revision 365274) @@ -1,116 +1,145 @@ .\"- .\" SPDX-License-Identifier: BSD-2-Clause .\" .\" Copyright (c) 2019 Ian Lepore .\" .\" 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 September 1, 2020 +.Dd September 2, 2020 .Dt LTC430X 4 .Os .Sh NAME .Nm ltc430x .Nd driver for LTC4305 and LTC4306 I2C mux chips .Sh SYNOPSIS To compile this driver into the kernel, place the following line in your kernel configuration file: .Bd -ragged -offset indent .Cd "device ltc430x" .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 ltc430x_load="YES" .Ed .Sh DESCRIPTION The .Nm driver supports the LTC4305 and LTC4306 I2C bus multiplexer (mux) chips. 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 conforms to the standard .Bk -words .Li i2c/i2c-mux-ltc4306.txt .Ek bindings document, except that the following optional properties are not currently supported and will be ignored if present: .Bl -bullet -compact -inset -offset indent .It enable-gpios .It gpio-controller .It #gpio-cells .It ltc,downstream-accelerators-enable .It ltc,upstream-accelerators-enable .El +.Pp +In addition, the following additional property is supported: +.Bl -tag -offset indent -width indent +.It Va freebsd,ctlreg2 +A value to store into the chip's control register 2 during initialization. +Consult the chip datasheet for the meaning of the various bits in +the register. +.El .Sh HINTS CONFIGURATION On a .Xr device.hints 5 -based system, these values are configurable for -.Nm : -.Bl -tag -width indent +based system, the following hints are required: +.Bl -tag -offset indent -width indent .It Va hint.ltc430x..at The upstream .Xr iicbus 4 the .Nm instance is attached to. .It Va hint.ltc430x..addr The slave address of the .Nm instance on the upstream bus. +.It Va hint.ltc430x..chip_type +The type of chip the driver is controlling. +Valid values are +.Dq ltc4305 +and +.Dq ltc4306 . .El .Pp +The following hints are optional: +.Bl -tag -offset indent -width indent +.It Va hint.ltc430x..ctlreg2 +A value to store into the chip's control register 2 during initialization. +Consult the chip datasheet for the meaning of the various bits in +the register. +This hint is optional; when missing, the driver does not update control +register 2. +.It Va hint.ltc430x..idle_disconnect +Whether to disconnect all downstream busses from the upstream bus when idle. +If set to zero, the most recently used downstream bus is left connected to +the upstream bus after IO completes. +Any non-zero value causes all downstream busses to be disconnected when idle. +This hint is optional; when missing, the driver behaves as if it were zero. +.El +.Pp When configured via hints, the driver automatically adds an iicbus instance for every downstream bus supported by the chip. -There is currently no way to indicate used versus unused channels. +There is currently no way to indicate used versus unused downstream channels. .Sh SEE ALSO .Xr iicbus 4 , .Xr iicmux 4 , .Sh HISTORY The .Nm driver first appeared in .Fx 13.0 . Index: head/sys/dev/iicbus/mux/ltc430x.c =================================================================== --- head/sys/dev/iicbus/mux/ltc430x.c (revision 365273) +++ head/sys/dev/iicbus/mux/ltc430x.c (revision 365274) @@ -1,221 +1,258 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2019 Ian Lepore * * 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 __FBSDID("$FreeBSD$"); #include "opt_platform.h" #include #include #include #include #include #include #include #include "iicbus_if.h" #include "iicmux_if.h" static struct chip_info { const char *partname; const char *description; int numchannels; } chip_infos[] = { {"ltc4305", "LTC4305 I2C Mux", 2}, {"ltc4306", "LTC4306 I2C Mux", 4}, }; #define CHIP_NONE (-1) #define CHIP_LTC4305 0 #define CHIP_LTC4306 1 #ifdef FDT #include #include #include static struct ofw_compat_data compat_data[] = { {"lltc,ltc4305", CHIP_LTC4305}, {"lltc,ltc4306", CHIP_LTC4306}, {NULL, CHIP_NONE} }; IICBUS_FDT_PNP_INFO(compat_data); #endif #include struct ltc430x_softc { struct iicmux_softc mux; bool idle_disconnect; }; /* * The datasheet doesn't name the registers, it calls them control register 0-3. */ #define LTC430X_CTLREG_0 0 #define LTC430X_CTLREG_1 1 #define LTC430X_CTLREG_2 2 +#define LTC430X_CR2_ENABLE_MW (1u << 3) /* Enable mass write address. */ #define LTC430X_CTLREG_3 3 static int ltc430x_bus_select(device_t dev, int busidx, struct iic_reqbus_data *rd) { struct ltc430x_softc *sc = device_get_softc(dev); uint8_t busbits; /* * 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. The upper bits of control register 3 activate the * downstream buses; bit 7 is the first bus, bit 6 the second, etc. */ if (busidx == IICMUX_SELECT_IDLE) { if (sc->idle_disconnect) busbits = 0; else return (0); } else { busbits = 1u << (7 - busidx); } /* * We have to add the IIC_RECURSIVE flag because the iicmux core has * already reserved the bus for us, and iicdev_writeto() is going to try * to reserve it again, which is allowed with the recursive flag. */ return (iicdev_writeto(dev, LTC430X_CTLREG_3, &busbits, sizeof(busbits), rd->flags | IIC_RECURSIVE)); } static int ltc430x_find_chiptype(device_t dev) { #ifdef FDT return (ofw_bus_search_compatible(dev, compat_data)->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(chip_infos); ++i) { if (strcasecmp(type, chip_infos[i].partname) == 0) { return (i); } } } return (CHIP_NONE); #endif } static int ltc430x_probe(device_t dev) { int type; #ifdef FDT if (!ofw_bus_status_okay(dev)) return (ENXIO); #endif type = ltc430x_find_chiptype(dev); if (type == CHIP_NONE) return (ENXIO); device_set_desc(dev, chip_infos[type].description); return (BUS_PROBE_DEFAULT); } static int ltc430x_attach(device_t dev) { struct ltc430x_softc *sc __unused; - int chip, err, numchan; + int chip, err, numchan, val; + uint8_t busbits, ctlreg2; sc = device_get_softc(dev); + busbits = 0; + ctlreg2 = LTC430X_CR2_ENABLE_MW; + + /* + * Check for the idle-disconnect and ctlreg2 options, first in FDT data, + * then allow them to be overriden by hints data. + */ #ifdef FDT phandle_t node; node = ofw_bus_get_node(dev); sc->idle_disconnect = OF_hasprop(node, "i2c-mux-idle-disconnect"); + + if (OF_getprop(macnode, "freebsd,ctlreg2", &val, sizeof(val)) > 0) { + ctlreg2 = val; + } #endif + if (resource_int_value(device_get_name(dev), device_get_unit(dev), + "idle_disconnect", &val) == 0) { + sc->idle_disconnect = val; + } + + if (resource_int_value(device_get_name(dev), device_get_unit(dev), + "ctlreg2", &val) == 0) { + ctlreg2 = val; + } + /* We found the chip type when probing, so now it "can't fail". */ if ((chip = ltc430x_find_chiptype(dev)) == CHIP_NONE) { device_printf(dev, "impossible: can't identify chip type\n"); return (ENXIO); } numchan = chip_infos[chip].numchannels; + /* Set control reg 2 with configured (or default) values. */ + iicdev_writeto(dev, LTC430X_CTLREG_2, &ctlreg2, sizeof(ctlreg2), + IIC_WAIT); + + /* If configured for idle-disconnect, ensure we start disconnected. */ + if (sc->idle_disconnect) { + iicdev_writeto(dev, LTC430X_CTLREG_3, &busbits, sizeof(busbits), + IIC_WAIT); + } + + /* + * Invoke the iicmux framework's attach code, and if it succeeds, invoke + * the probe and attach code of any child iicbus instances it added. + */ if ((err = iicmux_attach(dev, device_get_parent(dev), numchan)) == 0) - bus_generic_attach(dev); + bus_generic_attach(dev); return (err); } static int ltc430x_detach(device_t dev) { int err; if ((err = iicmux_detach(dev)) != 0) return (err); return (0); } static device_method_t ltc430x_methods[] = { /* device methods */ DEVMETHOD(device_probe, ltc430x_probe), DEVMETHOD(device_attach, ltc430x_attach), DEVMETHOD(device_detach, ltc430x_detach), /* iicmux methods */ DEVMETHOD(iicmux_bus_select, ltc430x_bus_select), DEVMETHOD_END }; static devclass_t ltc430x_devclass; DEFINE_CLASS_1(ltc430x, ltc430x_driver, ltc430x_methods, sizeof(struct ltc430x_softc), iicmux_driver); DRIVER_MODULE(ltc430x, iicbus, ltc430x_driver, ltc430x_devclass, 0, 0); #ifdef FDT DRIVER_MODULE(ofw_iicbus, ltc430x, ofw_iicbus_driver, ofw_iicbus_devclass, 0, 0); #else DRIVER_MODULE(iicbus, ltc430x, iicbus_driver, iicbus_devclass, 0, 0); #endif MODULE_DEPEND(ltc430x, iicmux, 1, 1, 1); MODULE_DEPEND(ltc430x, iicbus, 1, 1, 1);