diff options
author | 2023-10-10 14:33:42 +0000 | |
---|---|---|
committer | 2023-10-10 14:33:42 +0000 | |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/u-boot/drivers/i2c/muxes/pca954x.c | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/u-boot/drivers/i2c/muxes/pca954x.c')
-rw-r--r-- | roms/u-boot/drivers/i2c/muxes/pca954x.c | 177 |
1 files changed, 177 insertions, 0 deletions
diff --git a/roms/u-boot/drivers/i2c/muxes/pca954x.c b/roms/u-boot/drivers/i2c/muxes/pca954x.c new file mode 100644 index 000000000..55858cf65 --- /dev/null +++ b/roms/u-boot/drivers/i2c/muxes/pca954x.c @@ -0,0 +1,177 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2015 - 2016 Xilinx, Inc. + * Copyright (C) 2017 National Instruments Corp + * Written by Michal Simek + */ + +#include <common.h> +#include <dm.h> +#include <errno.h> +#include <i2c.h> +#include <log.h> +#include <malloc.h> +#include <asm/global_data.h> + +#include <asm-generic/gpio.h> + +DECLARE_GLOBAL_DATA_PTR; + +enum pca_type { + PCA9543, + PCA9544, + PCA9546, + PCA9547, + PCA9548, + PCA9646 +}; + +struct chip_desc { + u8 enable; /* Enable mask in ctl register (used for muxes only) */ + enum muxtype { + pca954x_ismux = 0, + pca954x_isswi, + } muxtype; + u32 width; +}; + +struct pca954x_priv { + u32 addr; /* I2C mux address */ + u32 width; /* I2C mux width - number of busses */ + struct gpio_desc gpio_mux_reset; +}; + +static const struct chip_desc chips[] = { + [PCA9543] = { + .muxtype = pca954x_isswi, + .width = 2, + }, + [PCA9544] = { + .enable = 0x4, + .muxtype = pca954x_ismux, + .width = 4, + }, + [PCA9546] = { + .muxtype = pca954x_isswi, + .width = 4, + }, + [PCA9547] = { + .enable = 0x8, + .muxtype = pca954x_ismux, + .width = 8, + }, + [PCA9548] = { + .muxtype = pca954x_isswi, + .width = 8, + }, + [PCA9646] = { + .muxtype = pca954x_isswi, + .width = 4, + }, +}; + +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); + const struct chip_desc *chip = &chips[dev_get_driver_data(mux)]; + uchar byte; + + if (chip->muxtype == pca954x_ismux) + byte = channel | chip->enable; + else + 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,pca9543", .data = PCA9543 }, + { .compatible = "nxp,pca9544", .data = PCA9544 }, + { .compatible = "nxp,pca9546", .data = PCA9546 }, + { .compatible = "nxp,pca9547", .data = PCA9547 }, + { .compatible = "nxp,pca9548", .data = PCA9548 }, + { .compatible = "nxp,pca9646", .data = PCA9646 }, + { } +}; + +static int pca954x_of_to_plat(struct udevice *dev) +{ + struct pca954x_priv *priv = dev_get_priv(dev); + const struct chip_desc *chip = &chips[dev_get_driver_data(dev)]; + + priv->addr = dev_read_u32_default(dev, "reg", 0); + if (!priv->addr) { + debug("MUX not found\n"); + return -ENODEV; + } + priv->width = chip->width; + + 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; +} + +static int pca954x_probe(struct udevice *dev) +{ + if (CONFIG_IS_ENABLED(DM_GPIO)) { + struct pca954x_priv *priv = dev_get_priv(dev); + int err; + + err = gpio_request_by_name(dev, "reset-gpios", 0, + &priv->gpio_mux_reset, GPIOD_IS_OUT); + + /* it's optional so only bail if we get a real error */ + if (err && (err != -ENOENT)) + return err; + + /* dm will take care of polarity */ + if (dm_gpio_is_valid(&priv->gpio_mux_reset)) + dm_gpio_set_value(&priv->gpio_mux_reset, 0); + } + + return 0; +} + +static int pca954x_remove(struct udevice *dev) +{ + if (CONFIG_IS_ENABLED(DM_GPIO)) { + struct pca954x_priv *priv = dev_get_priv(dev); + + if (dm_gpio_is_valid(&priv->gpio_mux_reset)) + dm_gpio_free(dev, &priv->gpio_mux_reset); + } + + return 0; +} + +U_BOOT_DRIVER(pca954x) = { + .name = "pca954x", + .id = UCLASS_I2C_MUX, + .of_match = pca954x_ids, + .probe = pca954x_probe, + .remove = pca954x_remove, + .ops = &pca954x_ops, + .of_to_plat = pca954x_of_to_plat, + .priv_auto = sizeof(struct pca954x_priv), +}; |