1 // SPDX-License-Identifier: GPL-2.0
3 * Theobroma Systems Mule I2C device multiplexer
5 * Copyright (C) 2024 Theobroma Systems Design und Consulting GmbH
8 #include <linux/i2c-mux.h>
10 #include <linux/module.h>
12 #include <linux/platform_device.h>
13 #include <linux/property.h>
14 #include <linux/regmap.h>
16 #define MULE_I2C_MUX_CONFIG_REG 0xff
17 #define MULE_I2C_MUX_DEFAULT_DEV 0x0
19 struct mule_i2c_reg_mux
{
20 struct regmap
*regmap
;
23 static int mule_i2c_mux_select(struct i2c_mux_core
*muxc
, u32 dev
)
25 struct mule_i2c_reg_mux
*mux
= muxc
->priv
;
27 return regmap_write(mux
->regmap
, MULE_I2C_MUX_CONFIG_REG
, dev
);
30 static int mule_i2c_mux_deselect(struct i2c_mux_core
*muxc
, u32 dev
)
32 return mule_i2c_mux_select(muxc
, MULE_I2C_MUX_DEFAULT_DEV
);
35 static void mule_i2c_mux_remove(void *data
)
37 struct i2c_mux_core
*muxc
= data
;
39 i2c_mux_del_adapters(muxc
);
41 mule_i2c_mux_deselect(muxc
, MULE_I2C_MUX_DEFAULT_DEV
);
44 static int mule_i2c_mux_probe(struct platform_device
*pdev
)
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
;
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
);
59 client
= to_i2c_client(mux_dev
->parent
);
61 muxc
= i2c_mux_alloc(client
->adapter
, mux_dev
, ndev
, sizeof(*priv
),
62 I2C_MUX_LOCKED
, mule_i2c_mux_select
, mule_i2c_mux_deselect
);
66 priv
= i2c_mux_priv(muxc
);
68 priv
->regmap
= dev_get_regmap(mux_dev
->parent
, NULL
);
70 return dev_err_probe(mux_dev
, -ENODEV
,
71 "No parent i2c register map\n");
73 platform_set_drvdata(pdev
, muxc
);
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).
80 ret
= mule_i2c_mux_select(muxc
, MULE_I2C_MUX_DEFAULT_DEV
);
82 return dev_err_probe(mux_dev
, ret
,
83 "Failed to write config register\n");
85 ret
= regmap_read(priv
->regmap
, MULE_I2C_MUX_CONFIG_REG
, &readback
);
87 return dev_err_probe(mux_dev
, ret
,
88 "Failed to read config register\n");
90 old_fw
= (readback
!= MULE_I2C_MUX_DEFAULT_DEV
);
92 ret
= devm_add_action_or_reset(mux_dev
, mule_i2c_mux_remove
, muxc
);
94 return dev_err_probe(mux_dev
, ret
,
95 "Failed to register mux remove\n");
97 /* Create device adapters */
98 for_each_child_of_node(mux_dev
->of_node
, dev
) {
101 ret
= of_property_read_u32(dev
, "reg", ®
);
103 return dev_err_probe(mux_dev
, ret
,
104 "No reg property found for %s\n",
105 of_node_full_name(dev
));
107 if (old_fw
&& reg
!= 0) {
109 "Mux is not supported, please update Mule FW\n");
113 ret
= mule_i2c_mux_select(muxc
, reg
);
116 "Device %d not supported, please update Mule FW\n", reg
);
120 ret
= i2c_mux_add_adapter(muxc
, 0, reg
);
125 mule_i2c_mux_deselect(muxc
, MULE_I2C_MUX_DEFAULT_DEV
);
130 static const struct of_device_id mule_i2c_mux_of_match
[] = {
131 { .compatible
= "tsd,mule-i2c-mux", },
134 MODULE_DEVICE_TABLE(of
, mule_i2c_mux_of_match
);
136 static struct platform_driver mule_i2c_mux_driver
= {
138 .name
= "mule-i2c-mux",
139 .of_match_table
= mule_i2c_mux_of_match
,
141 .probe
= mule_i2c_mux_probe
,
144 module_platform_driver(mule_i2c_mux_driver
);
146 MODULE_AUTHOR("Farouk Bouabid <farouk.bouabid@cherry.de>");
147 MODULE_DESCRIPTION("I2C mux driver for Theobroma Systems Mule");
148 MODULE_LICENSE("GPL");