i2c: muxes: Add support for TI PCA954X mux

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@xilinx.com>
Reviewed-by: Heiko Schocher <hs@denx.de>
Reviewed-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Michal Simek 2016-04-25 10:50:42 +02:00 committed by Heiko Schocher
parent ad72e7622b
commit d79ac32478
3 changed files with 90 additions and 0 deletions

View file

@ -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.

View file

@ -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

View file

@ -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),
};