summaryrefslogtreecommitdiff
path: root/drivers/i2c
diff options
context:
space:
mode:
authorFarouk Bouabid <farouk.bouabid@cherry.de>2024-09-06 18:54:13 +0300
committerAndi Shyti <andi.shyti@kernel.org>2024-09-10 01:36:47 +0300
commitd0f8e97866bf258b420ebf2b46755399ca01e585 (patch)
tree0debd33b3c557a1a910312311d58dcc85c9ca2b7 /drivers/i2c
parent4a875cf15427a1a83e9122e5be9a6b08937a5bc5 (diff)
downloadlinux-d0f8e97866bf258b420ebf2b46755399ca01e585.tar.xz
i2c: muxes: add support for tsd,mule-i2c multiplexer
Theobroma Systems Mule is an MCU that emulates a set of I2C devices, among which an amc6821 and devices that are reachable through an I2C-mux. The devices on the mux can be selected by writing the appropriate device number to an I2C config register (amc6821 reg 0xff). This driver is expected to be probed as a platform device with amc6821 as its parent i2c device. Add support for the mule-i2c-mux platform driver. The amc6821 driver support for the mux will be added in a later commit. Reviewed-by: Wolfram Sang <wsa+renesas@sang-engineering.com> Signed-off-by: Farouk Bouabid <farouk.bouabid@cherry.de> Signed-off-by: Andi Shyti <andi.shyti@kernel.org>
Diffstat (limited to 'drivers/i2c')
-rw-r--r--drivers/i2c/muxes/Kconfig16
-rw-r--r--drivers/i2c/muxes/Makefile1
-rw-r--r--drivers/i2c/muxes/i2c-mux-mule.c148
3 files changed, 165 insertions, 0 deletions
diff --git a/drivers/i2c/muxes/Kconfig b/drivers/i2c/muxes/Kconfig
index db1b9057612a..6d2f66810cdc 100644
--- a/drivers/i2c/muxes/Kconfig
+++ b/drivers/i2c/muxes/Kconfig
@@ -119,4 +119,20 @@ 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 "Theobroma Systems Mule I2C device multiplexer"
+ depends on OF && SENSORS_AMC6821
+ help
+ Mule is an MCU that emulates a set of I2C devices, among which
+ devices that are reachable through an I2C-mux. The devices on the mux
+ can be selected by writing the appropriate device number to an I2C
+ configuration register.
+
+ If you say yes to this option, support will be included for a
+ Theobroma Systems Mule I2C multiplexer. This driver provides access to
+ I2C devices connected on this 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..8e942470b35f
--- /dev/null
+++ b/drivers/i2c/muxes/i2c-mux-mule.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Theobroma Systems 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/platform_device.h>
+#include <linux/property.h>
+#include <linux/regmap.h>
+
+#define MULE_I2C_MUX_CONFIG_REG 0xff
+#define MULE_I2C_MUX_DEFAULT_DEV 0x0
+
+struct mule_i2c_reg_mux {
+ struct regmap *regmap;
+};
+
+static int mule_i2c_mux_select(struct i2c_mux_core *muxc, u32 dev)
+{
+ struct mule_i2c_reg_mux *mux = muxc->priv;
+
+ return regmap_write(mux->regmap, MULE_I2C_MUX_CONFIG_REG, dev);
+}
+
+static int mule_i2c_mux_deselect(struct i2c_mux_core *muxc, u32 dev)
+{
+ return mule_i2c_mux_select(muxc, MULE_I2C_MUX_DEFAULT_DEV);
+}
+
+static void mule_i2c_mux_remove(void *data)
+{
+ struct i2c_mux_core *muxc = data;
+
+ i2c_mux_del_adapters(muxc);
+
+ mule_i2c_mux_deselect(muxc, MULE_I2C_MUX_DEFAULT_DEV);
+}
+
+static int mule_i2c_mux_probe(struct platform_device *pdev)
+{
+ struct device *mux_dev = &pdev->dev;
+ struct mule_i2c_reg_mux *priv;
+ struct i2c_client *client;
+ 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(mux_dev->of_node);
+ dev_dbg(mux_dev, "%d devices on the mux\n", ndev);
+
+ client = to_i2c_client(mux_dev->parent);
+
+ muxc = i2c_mux_alloc(client->adapter, mux_dev, ndev, sizeof(*priv),
+ I2C_MUX_LOCKED, mule_i2c_mux_select, mule_i2c_mux_deselect);
+ if (!muxc)
+ return -ENOMEM;
+
+ priv = i2c_mux_priv(muxc);
+
+ priv->regmap = dev_get_regmap(mux_dev->parent, NULL);
+ if (IS_ERR(priv->regmap))
+ return dev_err_probe(mux_dev, PTR_ERR(priv->regmap),
+ "No parent i2c register map\n");
+
+ platform_set_drvdata(pdev, muxc);
+
+ /*
+ * MULE_I2C_MUX_DEFAULT_DEV 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 = mule_i2c_mux_select(muxc, MULE_I2C_MUX_DEFAULT_DEV);
+ if (ret)
+ return dev_err_probe(mux_dev, ret,
+ "Failed to write config register\n");
+
+ ret = regmap_read(priv->regmap, MULE_I2C_MUX_CONFIG_REG, &readback);
+ if (ret)
+ return dev_err_probe(mux_dev, ret,
+ "Failed to read config register\n");
+
+ old_fw = (readback != MULE_I2C_MUX_DEFAULT_DEV);
+
+ ret = devm_add_action_or_reset(mux_dev, mule_i2c_mux_remove, muxc);
+ if (ret)
+ return dev_err_probe(mux_dev, ret,
+ "Failed to register mux remove\n");
+
+ /* Create device adapters */
+ for_each_child_of_node(mux_dev->of_node, dev) {
+ u32 reg;
+
+ ret = of_property_read_u32(dev, "reg", &reg);
+ if (ret)
+ return dev_err_probe(mux_dev, ret,
+ "No reg property found for %s\n",
+ of_node_full_name(dev));
+
+ if (old_fw && reg != 0) {
+ dev_warn(mux_dev,
+ "Mux is not supported, please update Mule FW\n");
+ continue;
+ }
+
+ ret = mule_i2c_mux_select(muxc, reg);
+ if (ret) {
+ dev_warn(mux_dev,
+ "Device %d not supported, please update Mule FW\n", reg);
+ continue;
+ }
+
+ ret = i2c_mux_add_adapter(muxc, 0, reg);
+ if (ret)
+ return ret;
+ }
+
+ mule_i2c_mux_deselect(muxc, MULE_I2C_MUX_DEFAULT_DEV);
+
+ return 0;
+}
+
+static const struct of_device_id mule_i2c_mux_of_match[] = {
+ { .compatible = "tsd,mule-i2c-mux", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mule_i2c_mux_of_match);
+
+static struct platform_driver mule_i2c_mux_driver = {
+ .driver = {
+ .name = "mule-i2c-mux",
+ .of_match_table = mule_i2c_mux_of_match,
+ },
+ .probe = mule_i2c_mux_probe,
+};
+
+module_platform_driver(mule_i2c_mux_driver);
+
+MODULE_AUTHOR("Farouk Bouabid <farouk.bouabid@cherry.de>");
+MODULE_DESCRIPTION("I2C mux driver for Theobroma Systems Mule");
+MODULE_LICENSE("GPL");