Skip to content

Commit d0f8e97

Browse files
FaroukBouabidAndi Shyti
authored andcommitted
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 <[email protected]> Signed-off-by: Farouk Bouabid <[email protected]> Signed-off-by: Andi Shyti <[email protected]>
1 parent 4a875cf commit d0f8e97

File tree

3 files changed

+165
-0
lines changed

3 files changed

+165
-0
lines changed

drivers/i2c/muxes/Kconfig

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,20 @@ config I2C_MUX_MLXCPLD
119119
This driver can also be built as a module. If so, the module
120120
will be called i2c-mux-mlxcpld.
121121

122+
config I2C_MUX_MULE
123+
tristate "Theobroma Systems Mule I2C device multiplexer"
124+
depends on OF && SENSORS_AMC6821
125+
help
126+
Mule is an MCU that emulates a set of I2C devices, among which
127+
devices that are reachable through an I2C-mux. The devices on the mux
128+
can be selected by writing the appropriate device number to an I2C
129+
configuration register.
130+
131+
If you say yes to this option, support will be included for a
132+
Theobroma Systems Mule I2C multiplexer. This driver provides access to
133+
I2C devices connected on this mux.
134+
135+
This driver can also be built as a module. If so, the module
136+
will be called i2c-mux-mule.
137+
122138
endmenu

drivers/i2c/muxes/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ obj-$(CONFIG_I2C_MUX_GPIO) += i2c-mux-gpio.o
1010
obj-$(CONFIG_I2C_MUX_GPMUX) += i2c-mux-gpmux.o
1111
obj-$(CONFIG_I2C_MUX_LTC4306) += i2c-mux-ltc4306.o
1212
obj-$(CONFIG_I2C_MUX_MLXCPLD) += i2c-mux-mlxcpld.o
13+
obj-$(CONFIG_I2C_MUX_MULE) += i2c-mux-mule.o
1314
obj-$(CONFIG_I2C_MUX_PCA9541) += i2c-mux-pca9541.o
1415
obj-$(CONFIG_I2C_MUX_PCA954x) += i2c-mux-pca954x.o
1516
obj-$(CONFIG_I2C_MUX_PINCTRL) += i2c-mux-pinctrl.o

drivers/i2c/muxes/i2c-mux-mule.c

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/*
3+
* Theobroma Systems Mule I2C device multiplexer
4+
*
5+
* Copyright (C) 2024 Theobroma Systems Design und Consulting GmbH
6+
*/
7+
8+
#include <linux/i2c-mux.h>
9+
#include <linux/i2c.h>
10+
#include <linux/module.h>
11+
#include <linux/of.h>
12+
#include <linux/platform_device.h>
13+
#include <linux/property.h>
14+
#include <linux/regmap.h>
15+
16+
#define MULE_I2C_MUX_CONFIG_REG 0xff
17+
#define MULE_I2C_MUX_DEFAULT_DEV 0x0
18+
19+
struct mule_i2c_reg_mux {
20+
struct regmap *regmap;
21+
};
22+
23+
static int mule_i2c_mux_select(struct i2c_mux_core *muxc, u32 dev)
24+
{
25+
struct mule_i2c_reg_mux *mux = muxc->priv;
26+
27+
return regmap_write(mux->regmap, MULE_I2C_MUX_CONFIG_REG, dev);
28+
}
29+
30+
static int mule_i2c_mux_deselect(struct i2c_mux_core *muxc, u32 dev)
31+
{
32+
return mule_i2c_mux_select(muxc, MULE_I2C_MUX_DEFAULT_DEV);
33+
}
34+
35+
static void mule_i2c_mux_remove(void *data)
36+
{
37+
struct i2c_mux_core *muxc = data;
38+
39+
i2c_mux_del_adapters(muxc);
40+
41+
mule_i2c_mux_deselect(muxc, MULE_I2C_MUX_DEFAULT_DEV);
42+
}
43+
44+
static int mule_i2c_mux_probe(struct platform_device *pdev)
45+
{
46+
struct device *mux_dev = &pdev->dev;
47+
struct mule_i2c_reg_mux *priv;
48+
struct i2c_client *client;
49+
struct i2c_mux_core *muxc;
50+
struct device_node *dev;
51+
unsigned int readback;
52+
int ndev, ret;
53+
bool old_fw;
54+
55+
/* Count devices on the mux */
56+
ndev = of_get_child_count(mux_dev->of_node);
57+
dev_dbg(mux_dev, "%d devices on the mux\n", ndev);
58+
59+
client = to_i2c_client(mux_dev->parent);
60+
61+
muxc = i2c_mux_alloc(client->adapter, mux_dev, ndev, sizeof(*priv),
62+
I2C_MUX_LOCKED, mule_i2c_mux_select, mule_i2c_mux_deselect);
63+
if (!muxc)
64+
return -ENOMEM;
65+
66+
priv = i2c_mux_priv(muxc);
67+
68+
priv->regmap = dev_get_regmap(mux_dev->parent, NULL);
69+
if (IS_ERR(priv->regmap))
70+
return dev_err_probe(mux_dev, PTR_ERR(priv->regmap),
71+
"No parent i2c register map\n");
72+
73+
platform_set_drvdata(pdev, muxc);
74+
75+
/*
76+
* MULE_I2C_MUX_DEFAULT_DEV is guaranteed to exist on all old and new
77+
* mule fw. Mule fw without mux support will accept write ops to the
78+
* config register, but readback returns 0xff (register not updated).
79+
*/
80+
ret = mule_i2c_mux_select(muxc, MULE_I2C_MUX_DEFAULT_DEV);
81+
if (ret)
82+
return dev_err_probe(mux_dev, ret,
83+
"Failed to write config register\n");
84+
85+
ret = regmap_read(priv->regmap, MULE_I2C_MUX_CONFIG_REG, &readback);
86+
if (ret)
87+
return dev_err_probe(mux_dev, ret,
88+
"Failed to read config register\n");
89+
90+
old_fw = (readback != MULE_I2C_MUX_DEFAULT_DEV);
91+
92+
ret = devm_add_action_or_reset(mux_dev, mule_i2c_mux_remove, muxc);
93+
if (ret)
94+
return dev_err_probe(mux_dev, ret,
95+
"Failed to register mux remove\n");
96+
97+
/* Create device adapters */
98+
for_each_child_of_node(mux_dev->of_node, dev) {
99+
u32 reg;
100+
101+
ret = of_property_read_u32(dev, "reg", &reg);
102+
if (ret)
103+
return dev_err_probe(mux_dev, ret,
104+
"No reg property found for %s\n",
105+
of_node_full_name(dev));
106+
107+
if (old_fw && reg != 0) {
108+
dev_warn(mux_dev,
109+
"Mux is not supported, please update Mule FW\n");
110+
continue;
111+
}
112+
113+
ret = mule_i2c_mux_select(muxc, reg);
114+
if (ret) {
115+
dev_warn(mux_dev,
116+
"Device %d not supported, please update Mule FW\n", reg);
117+
continue;
118+
}
119+
120+
ret = i2c_mux_add_adapter(muxc, 0, reg);
121+
if (ret)
122+
return ret;
123+
}
124+
125+
mule_i2c_mux_deselect(muxc, MULE_I2C_MUX_DEFAULT_DEV);
126+
127+
return 0;
128+
}
129+
130+
static const struct of_device_id mule_i2c_mux_of_match[] = {
131+
{ .compatible = "tsd,mule-i2c-mux", },
132+
{},
133+
};
134+
MODULE_DEVICE_TABLE(of, mule_i2c_mux_of_match);
135+
136+
static struct platform_driver mule_i2c_mux_driver = {
137+
.driver = {
138+
.name = "mule-i2c-mux",
139+
.of_match_table = mule_i2c_mux_of_match,
140+
},
141+
.probe = mule_i2c_mux_probe,
142+
};
143+
144+
module_platform_driver(mule_i2c_mux_driver);
145+
146+
MODULE_AUTHOR("Farouk Bouabid <[email protected]>");
147+
MODULE_DESCRIPTION("I2C mux driver for Theobroma Systems Mule");
148+
MODULE_LICENSE("GPL");

0 commit comments

Comments
 (0)