[U-Boot] [PATCH v2] i2c: muxes: Add support for TI PCA954X mux

Ben Stoltz stoltz at google.com
Mon Apr 25 20:01:23 CEST 2016


Looking at the TI PCA9544 datasheet, this looks like a well behaved part
that should avoid some of the problems I've seen with the NXP954x series.
If a design incorporates GPIO control of the Vcc line into these parts,
then it should be able to deal with stuck downstream busses that cannot be
recovered through the usual inband methods (9-clocks, SMBUS holding clock
low for x ms, etc.)

There could be  a stub for toggling Vcc to get POR, or for clearing a
downstream bus, but that gets into board specific implementation details.

On Mon, Apr 25, 2016 at 1:50 AM Michal Simek <michal.simek at xilinx.com>
wrote:

> Add support for common TI i2c mux which is available on ZynqMP zcu102
> board.
> DM i2c mux core code is selecting/deselecting bus before/after
> every command is performed that's why only one channel is active at a
> time. That's also the reason why deselect is just disable all available
> channels.
>
> Signed-off-by: Michal Simek <michal.simek at xilinx.com>
> Reviewed-by: Heiko Schocher <hs at denx.de>
> Reviewed-by: Simon Glass <sjg at chromium.org>
> ---
>
> Changes in v2:
> - use fdtdec_get_int() for getting i2c address instead of dev_get_addr()
>   which is designed for MMIO accesses and requires non zero size cells.
> - Change returned error code - Simon
> - Use 954x instead of 954X and 95xx - Michal
> - Extend Kconfig description - Simon
> - Add comments to private structure - Simon
>
> Simon, Heiko: Feel free to comment this version and reject your tag.
>
> ---
>  drivers/i2c/muxes/Kconfig   | 10 ++++++
>  drivers/i2c/muxes/Makefile  |  1 +
>  drivers/i2c/muxes/pca954x.c | 79
> +++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 90 insertions(+)
>  create mode 100644 drivers/i2c/muxes/pca954x.c
>
> diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
> index f959d9de9e8b..48900ed2afc5 100644
> --- a/drivers/i2c/muxes/Kconfig
> +++ b/drivers/i2c/muxes/Kconfig
> @@ -24,3 +24,13 @@ config I2C_ARB_GPIO_CHALLENGE
>           I2C multimaster arbitration scheme using GPIOs and a challenge &
>           response mechanism where masters have to claim the bus by
> asserting
>           a GPIO.
> +
> +config I2C_MUX_PCA954x
> +       tristate "TI PCA954x I2C Mux/switches"
> +       depends on I2C_MUX
> +       help
> +         If you say yes here you get support for the TI PCA954x
> +         I2C mux/switch devices. It is x width I2C multiplexer which
> enables to
> +         paritioning I2C bus and connect multiple devices with the same
> address
> +         to the same I2C controller where driver handles proper routing to
> +         target i2c device. PCA9544 and PCA9548 are supported.
> diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
> index 47c1240d7e9e..0811add4216e 100644
> --- a/drivers/i2c/muxes/Makefile
> +++ b/drivers/i2c/muxes/Makefile
> @@ -5,3 +5,4 @@
>  #
>  obj-$(CONFIG_I2C_ARB_GPIO_CHALLENGE) += i2c-arb-gpio-challenge.o
>  obj-$(CONFIG_$(SPL_)I2C_MUX) += i2c-mux-uclass.o
> +obj-$(CONFIG_I2C_MUX_PCA954x) += pca954x.o
> diff --git a/drivers/i2c/muxes/pca954x.c b/drivers/i2c/muxes/pca954x.c
> new file mode 100644
> index 000000000000..7e0d2da4d605
> --- /dev/null
> +++ b/drivers/i2c/muxes/pca954x.c
> @@ -0,0 +1,79 @@
> +/*
> + * Copyright (C) 2015 - 2016 Xilinx, Inc.
> + * Written by Michal Simek
> + *
> + * SPDX-License-Identifier:    GPL-2.0+
> + */
> +
> +#include <common.h>
> +#include <dm.h>
> +#include <errno.h>
> +#include <i2c.h>
> +#include <asm/gpio.h>
> +
> +DECLARE_GLOBAL_DATA_PTR;
> +
> +struct pca954x_priv {
> +       u32 addr; /* I2C mux address */
> +       u32 width; /* I2C mux width - number of busses */
> +};
> +
> +static int pca954x_deselect(struct udevice *mux, struct udevice *bus,
> +                           uint channel)
> +{
> +       struct pca954x_priv *priv = dev_get_priv(mux);
> +       uchar byte = 0;
> +
> +       return dm_i2c_write(mux, priv->addr, &byte, 1);
> +}
> +
> +static int pca954x_select(struct udevice *mux, struct udevice *bus,
> +                         uint channel)
> +{
> +       struct pca954x_priv *priv = dev_get_priv(mux);
> +       uchar byte = 1 << channel;
> +
> +       return dm_i2c_write(mux, priv->addr, &byte, 1);
> +}
> +
> +static const struct i2c_mux_ops pca954x_ops = {
> +       .select = pca954x_select,
> +       .deselect = pca954x_deselect,
> +};
> +
> +static const struct udevice_id pca954x_ids[] = {
> +       { .compatible = "nxp,pca9548", .data = (ulong)8 },
> +       { .compatible = "nxp,pca9544", .data = (ulong)4 },
> +       { }
> +};
> +
> +static int pca954x_ofdata_to_platdata(struct udevice *dev)
> +{
> +       struct pca954x_priv *priv = dev_get_priv(dev);
> +
> +       priv->addr = fdtdec_get_int(gd->fdt_blob, dev->of_offset, "reg",
> 0);
> +       if (!priv->addr) {
> +               debug("MUX not found\n");
> +               return -ENODEV;
> +       }
> +       priv->width = dev_get_driver_data(dev);
> +
> +       if (!priv->width) {
> +               debug("No I2C MUX width specified\n");
> +               return -EINVAL;
> +       }
> +
> +       debug("Device %s at 0x%x with width %d\n",
> +             dev->name, priv->addr, priv->width);
> +
> +       return 0;
> +}
> +
> +U_BOOT_DRIVER(pca954x) = {
> +       .name = "pca954x",
> +       .id = UCLASS_I2C_MUX,
> +       .of_match = pca954x_ids,
> +       .ops = &pca954x_ops,
> +       .ofdata_to_platdata = pca954x_ofdata_to_platdata,
> +       .priv_auto_alloc_size = sizeof(struct pca954x_priv),
> +};
> --
> 1.9.1
>
>


More information about the U-Boot mailing list