This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

TCA9545A: debug TCA9545A based on RK3399

Part Number: TCA9545A

Now we are debugging TCA9545A based on RK3399. At present, we only know how to open the access I2C, but we do not know how to work and whether a driver is needed. If necessary, could you help to provide Linux driver and configuration?

thanks

  • The device tree configuration is similar to any other I²C mux, with:

    compatible = "nxp,pca9545"
  • Referring to PCA9548, I did not find the I2C address in TCA9545. Is there no i2C address in tCA9545?

  • i2c-mux@74 {
    compatible = "nxp,pca9548";
    #address-cells = <1>;
    #size-cells = <0>;
    reg = <0x74>;

  • As shown in section 8.6.1 of the datasheet, the TCA9545A has the address 0x70/0x71/0x72/0x73, depending on the address pins. Why are you mentioning the PCA9548, which is a different device?

  • Now I can only refer to pCA9545 configuration, now i2C-MUx-PCA9541.c modified as the driver, there are several more devices under /dev/i2c, but I hung i2C-sensor under several generated devices, there is no effect, I feel that the chip does not work at all

    Is there something wrong with my configuration?

    + tca9545@73 {
    + compatible = "tca9545";
    + #address-cells = <1>;
    + #size-cells = <0>;
    + reg = <0x73>;
    + interrupt-parent = <&gpio2>;
    + interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
    + interrupt-controller;
    + reset-gpios = <&gpio2 3 GPIO_ACTIVE_HIGH>;
    + #interrupt-cells = <4>;
    +
    + i2c@1 {
    + #address-cells = <1>;
    + #size-cells = <0>;
    + reg = <1>;
    + tsl2562@29 {
    + compatible = "grove,tsl2561";
    + reg = <0x29>;
    + };
    + };

    root@linaro-alip:~# i2cdetect -l
    i2c-0 i2c rk3x-i2c I2C adapter
    i2c-1 i2c rk3x-i2c I2C adapter
    i2c-2 i2c rk3x-i2c I2C adapter
    i2c-4 i2c rk3x-i2c I2C adapter
    i2c-7 i2c rk3x-i2c I2C adapter
    i2c-9 i2c i2c-2-mux (chan_id 0) I2C adapter
    i2c-10 i2c i2c-2-mux (chan_id 1) I2C adapter
    i2c-11 i2c i2c-2-mux (chan_id 2) I2C adapter
    i2c-12 i2c i2c-2-mux (chan_id 3) I2C adapter
    i2c-13 i2c DesignWare HDMI I2C adapter
    i2c-14 i2c DP-AUX I2C adapter
    root@linaro-alip:~#

  • Shouldn't the compatible entry be "nxp,pca9545"?

    I do not know your board. Please show a schematic of the I²C parts.

  • i2c-mux-pca954x.c
    /*
     * I2C multiplexer
     *
     * Copyright (c) 2008-2009 Rodolfo Giometti <giometti@linux.it>
     * Copyright (c) 2008-2009 Eurotech S.p.A. <info@eurotech.it>
     *
     * This module supports the PCA954x series of I2C multiplexer/switch chips
     * made by Philips Semiconductors.
     * This includes the:
     *	 PCA9540, PCA9542, PCA9543, PCA9544, PCA9545, PCA9546, PCA9547
     *	 and PCA9548.
     *
     * These chips are all controlled via the I2C bus itself, and all have a
     * single 8-bit register. The upstream "parent" bus fans out to two,
     * four, or eight downstream busses or channels; which of these
     * are selected is determined by the chip type and register contents. A
     * mux can select only one sub-bus at a time; a switch can select any
     * combination simultaneously.
     *
     * Based on:
     *	pca954x.c from Kumar Gala <galak@kernel.crashing.org>
     * Copyright (C) 2006
     *
     * Based on:
     *	pca954x.c from Ken Harrenstien
     * Copyright (C) 2004 Google, Inc. (Ken Harrenstien)
     *
     * Based on:
     *	i2c-virtual_cb.c from Brian Kuschak <bkuschak@yahoo.com>
     * and
     *	pca9540.c from Jean Delvare <jdelvare@suse.de>.
     *
     * This file is licensed under the terms of the GNU General Public
     * License version 2. This program is licensed "as is" without any
     * warranty of any kind, whether express or implied.
     */
    
    #include <linux/device.h>
    #include <linux/gpio/consumer.h>
    #include <linux/i2c.h>
    #include <linux/i2c-mux.h>
    #include <linux/i2c/pca954x.h>
    #include <linux/module.h>
    #include <linux/of.h>
    #include <linux/pm.h>
    #include <linux/slab.h>
    
    #define PCA954X_MAX_NCHANS 8
    
    enum pca_type {
    	pca_9540,
    	pca_9542,
    	pca_9543,
    	pca_9544,
    	pca_9545,
    	tca_9545,
    	pca_9546,
    	pca_9547,
    	pca_9548,
    };
    
    struct pca954x {
    	enum pca_type type;
    	struct i2c_adapter *virt_adaps[PCA954X_MAX_NCHANS];
    
    	u8 last_chan;		/* last register value */
    };
    
    struct chip_desc {
    	u8 nchans;
    	u8 enable;	/* used for muxes only */
    	enum muxtype {
    		pca954x_ismux = 0,
    		pca954x_isswi
    	} muxtype;
    };
    
    /* Provide specs for the PCA954x types we know about */
    static const struct chip_desc chips[] = {
    	[pca_9540] = {
    		.nchans = 2,
    		.enable = 0x4,
    		.muxtype = pca954x_ismux,
    	},
    	[pca_9543] = {
    		.nchans = 2,
    		.muxtype = pca954x_isswi,
    	},
    	[pca_9544] = {
    		.nchans = 4,
    		.enable = 0x4,
    		.muxtype = pca954x_ismux,
    	},
    	[pca_9545] = {
    		.nchans = 4,
    		.muxtype = pca954x_isswi,
    	},
    	[tca_9545] = {
                    .nchans = 4,
                    .muxtype = pca954x_isswi,
            },
    	[pca_9547] = {
    		.nchans = 8,
    		.enable = 0x8,
    		.muxtype = pca954x_ismux,
    	},
    	[pca_9548] = {
    		.nchans = 8,
    		.muxtype = pca954x_isswi,
    	},
    };
    
    static const struct i2c_device_id pca954x_id[] = {
    	{ "pca9540", pca_9540 },
    	{ "pca9542", pca_9540 },
    	{ "pca9543", pca_9543 },
    	{ "pca9544", pca_9544 },
    	{ "pca9545", pca_9545 },
    	{ "tca9545", tca_9545 },
    	{ "pca9546", pca_9545 },
    	{ "pca9547", pca_9547 },
    	{ "pca9548", pca_9548 },
    	{ }
    };
    MODULE_DEVICE_TABLE(i2c, pca954x_id);
    
    /* Write to mux register. Don't use i2c_transfer()/i2c_smbus_xfer()
       for this as they will try to lock adapter a second time */
    static int pca954x_reg_write(struct i2c_adapter *adap,
    			     struct i2c_client *client, u8 val)
    {
    	int ret = -ENODEV;
    
    	if (adap->algo->master_xfer) {
    		struct i2c_msg msg;
    		char buf[1];
    
    		msg.addr = client->addr;
    		msg.flags = 0;
    		msg.len = 1;
    		buf[0] = val;
    		msg.buf = buf;
    		ret = __i2c_transfer(adap, &msg, 1);
    	} else {
    		union i2c_smbus_data data;
    		ret = adap->algo->smbus_xfer(adap, client->addr,
    					     client->flags,
    					     I2C_SMBUS_WRITE,
    					     val, I2C_SMBUS_BYTE, &data);
    	}
    
    	return ret;
    }
    
    static int pca954x_select_chan(struct i2c_adapter *adap,
    			       void *client, u32 chan)
    {
    	struct pca954x *data = i2c_get_clientdata(client);
    	const struct chip_desc *chip = &chips[data->type];
    	u8 regval;
    	int ret = 0;
    
    	/* we make switches look like muxes, not sure how to be smarter */
    	if (chip->muxtype == pca954x_ismux)
    		regval = chan | chip->enable;
    	else
    		regval = 1 << chan;
    
    	/* Only select the channel if its different from the last channel */
    	if (data->last_chan != regval) {
    		ret = pca954x_reg_write(adap, client, regval);
    		data->last_chan = regval;
    	}
    
    	return ret;
    }
    
    static int pca954x_deselect_mux(struct i2c_adapter *adap,
    				void *client, u32 chan)
    {
    	struct pca954x *data = i2c_get_clientdata(client);
    
    	/* Deselect active channel */
    	data->last_chan = 0;
    	return pca954x_reg_write(adap, client, data->last_chan);
    }
    
    /*
     * I2C init/probing/exit functions
     */
    static int pca954x_probe(struct i2c_client *client,
    			 const struct i2c_device_id *id)
    {
    	struct i2c_adapter *adap = to_i2c_adapter(client->dev.parent);
    	struct pca954x_platform_data *pdata = dev_get_platdata(&client->dev);
    	struct device_node *of_node = client->dev.of_node;
    	bool idle_disconnect_dt;
    	struct gpio_desc *gpio;
    	int num, force, class;
    	struct pca954x *data;
    	int ret;
    
    	printk(KERN_ERR "pca954x_probe\n");
    
    	if (!i2c_check_functionality(adap, I2C_FUNC_SMBUS_BYTE))
    		return -ENODEV;
    
    	data = devm_kzalloc(&client->dev, sizeof(struct pca954x), GFP_KERNEL);
    	if (!data)
    		return -ENOMEM;
    
    	i2c_set_clientdata(client, data);
    	/* Get the mux out of reset if a reset GPIO is specified. */
    	gpio = devm_gpiod_get_optional(&client->dev, "reset", GPIOD_OUT_LOW);
    	if (IS_ERR(gpio))
    		return PTR_ERR(gpio);
    
    	printk(KERN_ERR "pca954x_probe set get reset\n");
    
    	/* Write the mux register at addr to verify
    	 * that the mux is in fact present. This also
    	 * initializes the mux to disconnected state.
    	 */
    	#if 0
    	if (i2c_smbus_write_byte(client, 0) < 0) {
    		dev_warn(&client->dev, "probe failed\n");
    		return -ENODEV;
    	}
    	#endif
    
    	data->type = id->driver_data;
    	data->last_chan = 0;		   /* force the first selection */
    
    	printk(KERN_ERR "pca954x_probe data->type:%d\n",data->type);
    
    	idle_disconnect_dt = of_node &&
    		of_property_read_bool(of_node, "i2c-mux-idle-disconnect");
    
    	/* Now create an adapter for each channel */
    	for (num = 0; num < chips[data->type].nchans; num++) {
    		bool idle_disconnect_pd = false;
    
    		force = 0;			  /* dynamic adap number */
    		class = 0;			  /* no class by default */
    		if (pdata) {
    			if (num < pdata->num_modes) {
    				/* force static number */
    				force = pdata->modes[num].adap_id;
    				class = pdata->modes[num].class;
    			} else
    				/* discard unconfigured channels */
    				break;
    			idle_disconnect_pd = pdata->modes[num].deselect_on_exit;
    		}
    
    		data->virt_adaps[num] =
    			i2c_add_mux_adapter(adap, &client->dev, client,
    				force, num, class, pca954x_select_chan,
    				(idle_disconnect_pd || idle_disconnect_dt)
    					? pca954x_deselect_mux : NULL);
    		dev_err(&client->dev,"register multiplexed adapter %d as bus %d\n", num, force);
    
    		if (data->virt_adaps[num] == NULL) {
    			ret = -ENODEV;
    			dev_err(&client->dev,
    				"failed to register multiplexed adapter"
    				" %d as bus %d\n", num, force);
    			goto virt_reg_failed;
    		}
    	}
    
    	dev_info(&client->dev,
    		 "registered %d multiplexed busses for I2C %s %s\n",
    		 num, chips[data->type].muxtype == pca954x_ismux
    				? "mux" : "switch", client->name);
    
    	return 0;
    
    virt_reg_failed:
    	for (num--; num >= 0; num--)
    		i2c_del_mux_adapter(data->virt_adaps[num]);
    	return ret;
    }
    
    static int pca954x_remove(struct i2c_client *client)
    {
    	struct pca954x *data = i2c_get_clientdata(client);
    	const struct chip_desc *chip = &chips[data->type];
    	int i;
    
    	for (i = 0; i < chip->nchans; ++i)
    		if (data->virt_adaps[i]) {
    			i2c_del_mux_adapter(data->virt_adaps[i]);
    			data->virt_adaps[i] = NULL;
    		}
    
    	return 0;
    }
    
    #ifdef CONFIG_PM_SLEEP
    static int pca954x_resume(struct device *dev)
    {
    	struct i2c_client *client = to_i2c_client(dev);
    	struct pca954x *data = i2c_get_clientdata(client);
    
    	data->last_chan = 0;
    	return i2c_smbus_write_byte(client, 0);
    }
    #endif
    
    static SIMPLE_DEV_PM_OPS(pca954x_pm, NULL, pca954x_resume);
    
    static struct i2c_driver pca954x_driver = {
    	.driver		= {
    		.name	= "pca954x",
    		.pm	= &pca954x_pm,
    	},
    	.probe		= pca954x_probe,
    	.remove		= pca954x_remove,
    	.id_table	= pca954x_id,
    };
    
    module_i2c_driver(pca954x_driver);
    
    MODULE_AUTHOR("Rodolfo Giometti <giometti@linux.it>");
    MODULE_DESCRIPTION("PCA954x I2C mux/switch driver");
    MODULE_LICENSE("GPL v2");
    

  • Above is the schematic diagram and Linux driver. I mounted a sensor on the generated I2C bus, but it didn't seem to work

  • VCC is too high. Section 9.2.1 of the datasheet says:

    The pass-gate transistors of the TCA9545A are constructed such that the VCC voltage can be used to limit the maximum voltage that is passed from one I²C bus to another.

    Figure 17 shows the voltage characteristics of the pass-gate transistors. In order for the TCA9545A to act as a voltage translator, the Vpass voltage must be equal to or lower than the lowest bus voltage. For example, if the main bus is running at 5 V and the downstream buses are 3.3 V and 2.7 V, Vpass must be equal to or below 2.7 V to effectively clamp the downstream bus voltages.

    As shown by the Vpass specification in the electrical characteristics table, to keep the switch output voltage below 1.8 V, VCC must be no higher than 2.7 V. You can simply use VCC = 1.8 V.

    If that still does not work, check with an oscilloscope whether the I²C signals arrive correctly at the upstream and downstream buses.