mbox series

[v3,0/7] Add Mule I2C multiplexer support

Message ID 20240611-dev-mule-i2c-mux-v3-0-08d26a28e001@cherry.de
Headers show
Series Add Mule I2C multiplexer support | expand

Message

Farouk Bouabid June 11, 2024, 11:43 a.m. UTC
Mule is an mcu that emulates a set of I2C devices which are reachable
through an I2C-mux.

The emulated devices share a single I2C address with the mux itself
where the requested register is what determines which logic is executed
(muxing logic or device logic):

1- The devices on the mux can be selected (muxing functionality) by
writing the appropriate device number to an I2C config register (0xff)
that is not used by any device logic.

2- Any access to a register other than the config register will be
handled by the previously selected device.

      +-------------------------------------------------------+
      |  Mule                                                 |
      |        +---------------+                              |
    ----+-(1)->|Config register|-----+                        |
      | |      +---------------+     |                        |
      | |                            V_                       |
      | |                            |  \          +--------+ |
      | |                            |   \-------->| dev #0 | |
      | |                            |   |         +--------+ |
      | |                            | M |-------->| dev #1 | |
      | +-----------(2)------------->| U |         +--------+ |
      |                              | X |-------->| dev #2 | |
      |                              |   |         +--------+ |
      |                              |   /-------->| dev #3 | |
      |                              |__/          +--------+ |
      +-------------------------------------------------------+

The current I2C-mux implementation does not allow the mux to use the
I2C address of a child device. As a workaround, A new I2C-adapter quirk is
introduced to skip the check for conflict between a child device and the
mux core I2C address when adding the child device.

This patch-series adds support for this multiplexer. Mule is integrated
as part of rk3399-puma, px30-ringneck, rk3588-tiger and rk3588-jaguar
boards.

Signed-off-by: Farouk Bouabid <farouk.bouabid@cherry.de>

Changes in v3:
- Change "i2c" in comments/commit-logs to "I2C"
- Fix long line-length
- Warn when "share_addr_with_children" is set and the Mux is not an I2C device
- Fix/stop propagating "I2C_AQ_SKIP_ADDR_CHECK" flag if "share_addr_with_children"
  is not set.
- Fix "old_fw" variable is used to indicate the reversed meaning.

- Link to v2: https://lore.kernel.org/r/20240506-dev-mule-i2c-mux-v2-0-a91c954f65d7@cherry.de

Changes in v2:
- Add i2c-adapter quirks to skip checking for conflict between the mux core
  and a child device address.
- Rename dt-binding to "tsd,mule-i2c-mux.yaml"
- Add Mule description to kconfig
- Fix indentation
- Move device table after probe

- Link to v1: https://lore.kernel.org/r/20240426-dev-mule-i2c-mux-v1-0-045a482f6ffb@theobroma-systems.com

---
Farouk Bouabid (7):
      i2c: mux: add the ability to share mux address with child nodes
      dt-bindings: i2c: mux: mule: add dt-bindings for mule i2c multiplexer
      i2c: muxes: add support for mule i2c multiplexer
      arm64: dts: rockchip: add mule i2c mux (0x18) on rk3399-puma
      arm64: dts: rockchip: add mule i2c mux (0x18) on rk3588-tiger
      arm64: dts: rockchip: add mule i2c mux (0x18) on px30-ringneck
      arm64: dts: rockchip: add mule i2c mux (0x18) on rk3588-jaguar

 .../devicetree/bindings/i2c/tsd,mule-i2c-mux.yaml  |  80 +++++++++++
 arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi    |  20 ++-
 arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi      |  20 ++-
 arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts     |  19 ++-
 arch/arm64/boot/dts/rockchip/rk3588-tiger.dtsi     |  19 ++-
 drivers/i2c/i2c-core-base.c                        |   6 +-
 drivers/i2c/i2c-mux.c                              |  48 ++++++-
 drivers/i2c/muxes/Kconfig                          |  18 +++
 drivers/i2c/muxes/Makefile                         |   1 +
 drivers/i2c/muxes/i2c-mux-mule.c                   | 157 +++++++++++++++++++++
 include/linux/i2c-mux.h                            |   1 +
 include/linux/i2c.h                                |   7 +
 12 files changed, 384 insertions(+), 12 deletions(-)
---
base-commit: 79c1f584335af42ce359ee3ff0f4e9cc324296ed
change-id: 20240404-dev-mule-i2c-mux-9103cde07021

Best regards,

Comments

Rob Herring June 11, 2024, 1:32 p.m. UTC | #1
On Tue, 11 Jun 2024 13:43:51 +0200, Farouk Bouabid wrote:
> Mule is an mcu that emulates a set of I2C devices which are reachable
> through an I2C-mux.
> 
> The emulated devices share a single I2C address with the mux itself
> where the requested register is what determines which logic is executed
> (muxing logic or device logic):
> 
> 1- The devices on the mux can be selected (muxing functionality) by
> writing the appropriate device number to an I2C config register (0xff)
> that is not used by any device logic.
> 
> 2- Any access to a register other than the config register will be
> handled by the previously selected device.
> 
>       +-------------------------------------------------------+
>       |  Mule                                                 |
>       |        +---------------+                              |
>     ----+-(1)->|Config register|-----+                        |
>       | |      +---------------+     |                        |
>       | |                            V_                       |
>       | |                            |  \          +--------+ |
>       | |                            |   \-------->| dev #0 | |
>       | |                            |   |         +--------+ |
>       | |                            | M |-------->| dev #1 | |
>       | +-----------(2)------------->| U |         +--------+ |
>       |                              | X |-------->| dev #2 | |
>       |                              |   |         +--------+ |
>       |                              |   /-------->| dev #3 | |
>       |                              |__/          +--------+ |
>       +-------------------------------------------------------+
> 
> The current I2C-mux implementation does not allow the mux to use the
> I2C address of a child device. As a workaround, A new I2C-adapter quirk is
> introduced to skip the check for conflict between a child device and the
> mux core I2C address when adding the child device.
> 
> This patch-series adds support for this multiplexer. Mule is integrated
> as part of rk3399-puma, px30-ringneck, rk3588-tiger and rk3588-jaguar
> boards.
> 
> Signed-off-by: Farouk Bouabid <farouk.bouabid@cherry.de>
> 
> Changes in v3:
> - Change "i2c" in comments/commit-logs to "I2C"
> - Fix long line-length
> - Warn when "share_addr_with_children" is set and the Mux is not an I2C device
> - Fix/stop propagating "I2C_AQ_SKIP_ADDR_CHECK" flag if "share_addr_with_children"
>   is not set.
> - Fix "old_fw" variable is used to indicate the reversed meaning.
> 
> - Link to v2: https://lore.kernel.org/r/20240506-dev-mule-i2c-mux-v2-0-a91c954f65d7@cherry.de
> 
> Changes in v2:
> - Add i2c-adapter quirks to skip checking for conflict between the mux core
>   and a child device address.
> - Rename dt-binding to "tsd,mule-i2c-mux.yaml"
> - Add Mule description to kconfig
> - Fix indentation
> - Move device table after probe
> 
> - Link to v1: https://lore.kernel.org/r/20240426-dev-mule-i2c-mux-v1-0-045a482f6ffb@theobroma-systems.com
> 
> ---
> Farouk Bouabid (7):
>       i2c: mux: add the ability to share mux address with child nodes
>       dt-bindings: i2c: mux: mule: add dt-bindings for mule i2c multiplexer
>       i2c: muxes: add support for mule i2c multiplexer
>       arm64: dts: rockchip: add mule i2c mux (0x18) on rk3399-puma
>       arm64: dts: rockchip: add mule i2c mux (0x18) on rk3588-tiger
>       arm64: dts: rockchip: add mule i2c mux (0x18) on px30-ringneck
>       arm64: dts: rockchip: add mule i2c mux (0x18) on rk3588-jaguar
> 
>  .../devicetree/bindings/i2c/tsd,mule-i2c-mux.yaml  |  80 +++++++++++
>  arch/arm64/boot/dts/rockchip/px30-ringneck.dtsi    |  20 ++-
>  arch/arm64/boot/dts/rockchip/rk3399-puma.dtsi      |  20 ++-
>  arch/arm64/boot/dts/rockchip/rk3588-jaguar.dts     |  19 ++-
>  arch/arm64/boot/dts/rockchip/rk3588-tiger.dtsi     |  19 ++-
>  drivers/i2c/i2c-core-base.c                        |   6 +-
>  drivers/i2c/i2c-mux.c                              |  48 ++++++-
>  drivers/i2c/muxes/Kconfig                          |  18 +++
>  drivers/i2c/muxes/Makefile                         |   1 +
>  drivers/i2c/muxes/i2c-mux-mule.c                   | 157 +++++++++++++++++++++
>  include/linux/i2c-mux.h                            |   1 +
>  include/linux/i2c.h                                |   7 +
>  12 files changed, 384 insertions(+), 12 deletions(-)
> ---
> base-commit: 79c1f584335af42ce359ee3ff0f4e9cc324296ed
> change-id: 20240404-dev-mule-i2c-mux-9103cde07021
> 
> Best regards,
> --
> Farouk Bouabid <farouk.bouabid@cherry.de>
> 
> 
> 


My bot found new DTB warnings on the .dts files added or changed in this
series.

Some warnings may be from an existing SoC .dtsi. Or perhaps the warnings
are fixed by another series. Ultimately, it is up to the platform
maintainer whether these warnings are acceptable or not. No need to reply
unless the platform maintainer has comments.

If you already ran DT checks and didn't see these error(s), then
make sure dt-schema is up to date:

  pip3 install dtschema --upgrade


New warnings running 'make CHECK_DTBS=y rockchip/rk3588-jaguar.dtb' for 20240611-dev-mule-i2c-mux-v3-0-08d26a28e001@cherry.de:

arch/arm64/boot/dts/rockchip/rk3588-jaguar.dtb: fan@18: '#cooling-cells' does not match any of the regexes: 'pinctrl-[0-9]+'
	from schema $id: http://devicetree.org/schemas/trivial-devices.yaml#
Farouk Bouabid June 11, 2024, 4:52 p.m. UTC | #2
Hi all,

On 11.06.24 13:43, Farouk Bouabid wrote:
> Mule is an MCU that emulates a set of I2C devices which are reachable
> through an I2C-mux.
>
> The emulated devices share a single I2C address with the mux itself
> where the requested register is what determines which logic is executed
> (mux logic or device logic):
>
> 1- The devices on the mux can be selected (mux function) by writing the
> appropriate device number to an I2C config register (0xff) that is not
> used by any device logic.
>
> 2- Any access to a register other than the config register will be
> handled by the previously selected device.
>
> Signed-off-by: Farouk Bouabid <farouk.bouabid@cherry.de>
> ---
>   drivers/i2c/muxes/Kconfig        |  18 +++++
>   drivers/i2c/muxes/Makefile       |   1 +
>   drivers/i2c/muxes/i2c-mux-mule.c | 157 +++++++++++++++++++++++++++++++++++++++
>   3 files changed, 176 insertions(+)
>
> diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
> index db1b9057612a..70876259796d 100644
> --- a/drivers/i2c/muxes/Kconfig
> +++ b/drivers/i2c/muxes/Kconfig
> @@ -119,4 +119,22 @@ config I2C_MUX_MLXCPLD
>   	  This driver can also be built as a module.  If so, the module
>   	  will be called i2c-mux-mlxcpld.
>   
> +config I2C_MUX_MULE
> +	tristate "Mule I2C device multiplexer"
> +	depends on OF
> +	help
> +	  Mule is an MCU that emulates a set of I2C devices which are reachable
> +	  through an I2C-mux.
> +
> +	  The emulated devices share a single I2C address with the mux itself
> +	  where the requested register is what determines which logic is executed
> +	  (mux logic or device logic).
> +
> +	  If you say yes to this option, support will be included for a
> +	  Mule I2C device multiplexer. This driver provides access to
> +	  I2C devices connected on the Mule I2C mux.
> +
> +	  This driver can also be built as a module.  If so, the module
> +	  will be called i2c-mux-mule.
> +
>   endmenu
> diff --git a/drivers/i2c/muxes/Makefile b/drivers/i2c/muxes/Makefile
> index 6d9d865e8518..4b24f49515a7 100644
> --- a/drivers/i2c/muxes/Makefile
> +++ b/drivers/i2c/muxes/Makefile
> @@ -10,6 +10,7 @@ obj-$(CONFIG_I2C_MUX_GPIO)	+= i2c-mux-gpio.o
>   obj-$(CONFIG_I2C_MUX_GPMUX)	+= i2c-mux-gpmux.o
>   obj-$(CONFIG_I2C_MUX_LTC4306)	+= i2c-mux-ltc4306.o
>   obj-$(CONFIG_I2C_MUX_MLXCPLD)	+= i2c-mux-mlxcpld.o
> +obj-$(CONFIG_I2C_MUX_MULE)	+= i2c-mux-mule.o
>   obj-$(CONFIG_I2C_MUX_PCA9541)	+= i2c-mux-pca9541.o
>   obj-$(CONFIG_I2C_MUX_PCA954x)	+= i2c-mux-pca954x.o
>   obj-$(CONFIG_I2C_MUX_PINCTRL)	+= i2c-mux-pinctrl.o
> diff --git a/drivers/i2c/muxes/i2c-mux-mule.c b/drivers/i2c/muxes/i2c-mux-mule.c
> new file mode 100644
> index 000000000000..db27fa560995
> --- /dev/null
> +++ b/drivers/i2c/muxes/i2c-mux-mule.c
> @@ -0,0 +1,157 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * Mule I2C device multiplexer
> + *
> + * Copyright (C) 2024 Theobroma Systems Design und Consulting GmbH
> + */
> +
> +#include <linux/i2c-mux.h>
> +#include <linux/i2c.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/property.h>
> +#include <linux/regmap.h>
> +
> +#define MUX_CONFIG_REG  0xff
> +#define MUX_DEFAULT_DEV 0x0
> +
> +struct mule_i2c_reg_mux {
> +	struct regmap *regmap;
> +};
> +
> +static const struct regmap_config mule_regmap_config = {
> +	.reg_bits = 8,
> +	.val_bits = 8,
> +};
> +
> +static inline int __mux_select(struct regmap *regmap, u32 dev)
> +{
> +	return regmap_write(regmap, MUX_CONFIG_REG, dev);
> +}
> +
> +static int mux_select(struct i2c_mux_core *muxc, u32 dev)
> +{
> +	struct mule_i2c_reg_mux *mux = muxc->priv;
> +
> +	return __mux_select(mux->regmap, dev);
> +}
> +
> +static int mux_deselect(struct i2c_mux_core *muxc, u32 dev)
> +{
> +	return mux_select(muxc, MUX_DEFAULT_DEV);
> +}
> +
> +static void mux_remove(void *data)
> +{
> +	struct i2c_mux_core *muxc = data;
> +
> +	i2c_mux_del_adapters(muxc);
> +
> +	mux_deselect(muxc, MUX_DEFAULT_DEV);
> +}
> +
> +static int mule_i2c_mux_probe(struct i2c_client *client)
> +{
> +	struct i2c_adapter *adap = client->adapter;
> +	struct mule_i2c_reg_mux *priv;
> +	struct i2c_mux_core *muxc;
> +	struct device_node *dev;
> +	unsigned int readback;
> +	int ndev, ret;
> +	bool old_fw;
> +
> +	/* Count devices on the mux */
> +	ndev = of_get_child_count(client->dev.of_node);
> +	dev_dbg(&client->dev, "%u devices on the mux\n", ndev);
> +
> +	muxc = i2c_mux_alloc(adap, &client->dev,
> +			     ndev, sizeof(*priv),
> +			     I2C_MUX_LOCKED,
> +			     mux_select, mux_deselect);
> +	if (!muxc)
> +		return -ENOMEM;
> +
> +	muxc->share_addr_with_children = 1;
> +	priv = i2c_mux_priv(muxc);
> +
> +	priv->regmap = devm_regmap_init_i2c(client, &mule_regmap_config);
> +	if (IS_ERR(priv->regmap))
> +		return dev_err_probe(&client->dev, PTR_ERR(priv->regmap),
> +				     "Failed to allocate i2c register map\n");
> +
> +	i2c_set_clientdata(client, muxc);
> +
> +	/*
> +	 * Mux 0 is guaranteed to exist on all old and new mule fw.
> +	 * mule fw without mux support will accept write ops to the
> +	 * config register, but readback returns 0xff (register not updated).
> +	 */
> +	ret = mux_select(muxc, 0);
> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_read(priv->regmap, MUX_CONFIG_REG, &readback);
> +	if (ret)
> +		return ret;
> +
> +	old_fw = (readback != 0);
> +
> +	ret = devm_add_action_or_reset(&client->dev, mux_remove, muxc);
> +	if (ret)
> +		return ret;
> +
> +	/* Create device adapters */
> +	for_each_child_of_node(client->dev.of_node, dev) {
> +		u32 reg;
> +
> +		ret = of_property_read_u32(dev, "reg", &reg);
> +		if (ret) {
> +			dev_err(&client->dev, "No reg property found for %s: %d\n",
> +				of_node_full_name(dev), ret);
> +			return ret;
> +		}
> +
> +		if (old_fw && reg != 0) {
> +			dev_warn(&client->dev,
> +				 "Mux %d not supported, please update Mule FW\n", reg);
> +			continue;
> +		}
> +
> +		ret = mux_select(muxc, reg);
> +		if (ret) {
> +			dev_warn(&client->dev,
> +				 "Mux %d not supported, please update Mule FW\n", reg);
> +			continue;
> +		}
> +
> +		ret = i2c_mux_add_adapter(muxc, 0, reg, 0);


The class parameter was recently removed from this function but I forgot 
to remove it. Sorry for the noise, I will send a v4 for this fix.


Cheers,

Farouk
Christophe JAILLET June 11, 2024, 5:56 p.m. UTC | #3
Le 11/06/2024 à 13:43, Farouk Bouabid a écrit :
> Mule is an MCU that emulates a set of I2C devices which are reachable
> through an I2C-mux.
> 
> The emulated devices share a single I2C address with the mux itself
> where the requested register is what determines which logic is executed
> (mux logic or device logic):
> 
> 1- The devices on the mux can be selected (mux function) by writing the
> appropriate device number to an I2C config register (0xff) that is not
> used by any device logic.
> 
> 2- Any access to a register other than the config register will be
> handled by the previously selected device.
> 
> Signed-off-by: Farouk Bouabid <farouk.bouabid@cherry.de>
> ---

Hi,

...

> +static int mule_i2c_mux_probe(struct i2c_client *client)
> +{
> +	struct i2c_adapter *adap = client->adapter;
> +	struct mule_i2c_reg_mux *priv;
> +	struct i2c_mux_core *muxc;
> +	struct device_node *dev;
> +	unsigned int readback;
> +	int ndev, ret;
> +	bool old_fw;
> +
> +	/* Count devices on the mux */
> +	ndev = of_get_child_count(client->dev.of_node);
> +	dev_dbg(&client->dev, "%u devices on the mux\n", ndev);

Should this be %d?

> +
> +	muxc = i2c_mux_alloc(adap, &client->dev,
> +			     ndev, sizeof(*priv),
> +			     I2C_MUX_LOCKED,
> +			     mux_select, mux_deselect);

Nitpick: this could be written with less lines.

> +	if (!muxc)
> +		return -ENOMEM;
> +
> +	muxc->share_addr_with_children = 1;
> +	priv = i2c_mux_priv(muxc);
> +
> +	priv->regmap = devm_regmap_init_i2c(client, &mule_regmap_config);
> +	if (IS_ERR(priv->regmap))
> +		return dev_err_probe(&client->dev, PTR_ERR(priv->regmap),
> +				     "Failed to allocate i2c register map\n");
> +
> +	i2c_set_clientdata(client, muxc);
> +
> +	/*
> +	 * Mux 0 is guaranteed to exist on all old and new mule fw.
> +	 * mule fw without mux support will accept write ops to the
> +	 * config register, but readback returns 0xff (register not updated).
> +	 */
> +	ret = mux_select(muxc, 0);

Should this 0 be MUX_DEFAULT_DEV (for consistency)?

> +	if (ret)
> +		return ret;
> +
> +	ret = regmap_read(priv->regmap, MUX_CONFIG_REG, &readback);
> +	if (ret)
> +		return ret;
> +
> +	old_fw = (readback != 0);
> +
> +	ret = devm_add_action_or_reset(&client->dev, mux_remove, muxc);
> +	if (ret)
> +		return ret;
> +
> +	/* Create device adapters */
> +	for_each_child_of_node(client->dev.of_node, dev) {
> +		u32 reg;
> +
> +		ret = of_property_read_u32(dev, "reg", &reg);
> +		if (ret) {
> +			dev_err(&client->dev, "No reg property found for %s: %d\n",
> +				of_node_full_name(dev), ret);

return dev_err_probe() as above?

> +			return ret;
> +		}
> +
> +		if (old_fw && reg != 0) {
> +			dev_warn(&client->dev,
> +				 "Mux %d not supported, please update Mule FW\n", reg);
> +			continue;
> +		}
> +
> +		ret = mux_select(muxc, reg);
> +		if (ret) {
> +			dev_warn(&client->dev,
> +				 "Mux %d not supported, please update Mule FW\n", reg);
> +			continue;
> +		}
> +
> +		ret = i2c_mux_add_adapter(muxc, 0, reg, 0);
> +		if (ret) {
> +			dev_err(&client->dev, "Failed to add i2c mux adapter %d: %d\n", reg, ret);

return dev_err_probe() as above?

> +			return ret;
> +		}
> +	}
> +
> +	mux_deselect(muxc, MUX_DEFAULT_DEV);
> +
> +	return 0;
> +}

...
Christophe JAILLET June 11, 2024, 6:01 p.m. UTC | #4
Le 11/06/2024 à 13:43, Farouk Bouabid a écrit :
> Allow the mux (if it's an I2C device) to have the same address as a child
> device. This is useful when the mux can only use an I2C address that is
> used by a child device because no other addresses are free to use.
> eg. the mux can only use address 0x18 which is used by amc6821 connected
> to the mux.
> 
> Signed-off-by: Farouk Bouabid <farouk.bouabid@cherry.de>
> ---

Hi,

2 nitpicks below.

> --- a/drivers/i2c/i2c-mux.c
> +++ b/drivers/i2c/i2c-mux.c
> @@ -334,7 +334,53 @@ int i2c_mux_add_adapter(struct i2c_mux_core *muxc,
>   	priv->adap.dev.parent = &parent->dev;
>   	priv->adap.retries = parent->retries;
>   	priv->adap.timeout = parent->timeout;
> -	priv->adap.quirks = parent->quirks;
> +
> +	struct i2c_adapter_quirks *quirks;

Should this be at the beginning of the function?

> +	/*
> +	 * When creating the adapter, the node devices are checked for I2C address
> +	 * match with other devices on the parent adapter, among which is the mux itself.
> +	 * If a match is found the node device is not probed successfully.
> +	 * Allow the mux to have the same address as a child device by skipping this check.
> +	 */
> +	if (muxc->share_addr_with_children) {
> +		struct i2c_client *client = to_i2c_client(muxc->dev);
> +
> +		if (muxc->dev->type != &i2c_client_type)
> +			dev_warn_once(muxc->dev, "Mux is not an I2C device\n");
> +
> +		quirks = devm_kzalloc(muxc->dev, sizeof(*quirks), GFP_KERNEL);
> +		if (!quirks)
> +			return -ENOMEM;
> +
> +		if (parent->quirks)
> +			memcpy(quirks, parent->quirks, sizeof(*quirks));
> +
> +		quirks->flags |= I2C_AQ_SKIP_ADDR_CHECK;
> +		quirks->skip_addr_in_parent = client->addr;
> +		priv->adap.quirks = quirks;
> +
> +	} else if (parent->quirks &&
> +		   parent->quirks->flags & I2C_AQ_SKIP_ADDR_CHECK) {
> +		/*
> +		 * Another I2C mux device can be a child of the Mule I2C mux.
> +		 * The former could probably not allow address conflict between
> +		 * its address and its own children addresses.
> +		 *
> +		 * For this purpose, do not propagate this flag unless
> +		 * share_addr_with_children is set.
> +		 */
> +		quirks = devm_kzalloc(muxc->dev, sizeof(*quirks), GFP_KERNEL);

devm_kmemdup()? (not sure it is a win)

> +		if (!quirks)
> +			return -ENOMEM;
> +
> +		memcpy(quirks, parent->quirks, sizeof(*quirks));
> +		quirks->flags &= ~I2C_AQ_SKIP_ADDR_CHECK;
> +		priv->adap.quirks = quirks;
> +
> +	} else {
> +		priv->adap.quirks = parent->quirks;
> +	}
> +
>   	if (muxc->mux_locked)
>   		priv->adap.lock_ops = &i2c_mux_lock_ops;
>   	else

...

CJ
Wolfram Sang June 11, 2024, 6:50 p.m. UTC | #5
> The class parameter was recently removed from this function but I forgot to
> remove it. Sorry for the noise, I will send a v4 for this fix.

Please wait for my comments to the series. Hopefully later this evening.
Wolfram Sang June 11, 2024, 10:12 p.m. UTC | #6
Hi Farouk,

first of all, thanks for the patches and tackling this problem. I have
to say that I have many concerns on high-level, though. I hope to be
able to give helpful recommendations.

> Mule is an mcu that emulates a set of I2C devices which are reachable
> through an I2C-mux.

I am not 100% convinced this is really a mux. Another possible DT
representation could be (pseudo-code):

	i2c-bus {
		mpu@42 {
			comptible = "mule";
			reg = <0x42>;

			subdev@0 {
				compatible = "subdev"
				reg = <0x00>;
			}

			subdev@1 {

			...

		}

	}

Dunno if MFD can handle that. Maybe someone else knows?

If all fails, I think you could write an I2C mux-driver which uses the
above DT snippet. It should then do:

- write the mule config register according to 'reg' of the subdev
- replace 'addr' in all 'i2c_msgs' to the addr of the parent mule device
- i2ctransfer
- restore 'addr' in all 'i2c_msgs' to the original addr

A little simiar of what i2c-atr.c does, check
Documentation/i2c/i2c-address-translators.rst

> The emulated devices share a single I2C address with the mux itself
> where the requested register is what determines which logic is executed
> (muxing logic or device logic):

This design is... unfortunate, if you ask me. But well, things happen.

> The current I2C-mux implementation does not allow the mux to use the
> I2C address of a child device. As a workaround, A new I2C-adapter quirk is
> introduced to skip the check for conflict between a child device and the
> mux core I2C address when adding the child device.

Not acceptable, sorry. The adapter itself is fine, so this is clearly
not an adapter quirk. The client is what is quirky. I don't want to
maintain patch 1 because of this one "creative" design of a client. I
think we can handle it outside of the I2C core.

So far understandable?

Happy hacking,

   Wolfram