[PATCH v13 8/8] i2c: mux: pca954x: use idle state from i2c_mux_core
From: Marcus Folkesson
Date: Thu Oct 15 2026 - 07:11:40 EST
The core now have support for keeping the track of the idle state.
Make use of that instead of handle this on our own.
Signed-off-by: Marcus Folkesson <marcus.folkesson@xxxxxxxxx>
---
drivers/i2c/muxes/i2c-mux-pca954x.c | 76 ++++++++++++++++++++++++-------------
1 file changed, 50 insertions(+), 26 deletions(-)
diff --git a/drivers/i2c/muxes/i2c-mux-pca954x.c b/drivers/i2c/muxes/i2c-mux-pca954x.c
index 8fca709ed279..87bde07374d2 100644
--- a/drivers/i2c/muxes/i2c-mux-pca954x.c
+++ b/drivers/i2c/muxes/i2c-mux-pca954x.c
@@ -52,7 +52,6 @@
#include <linux/reset.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
-#include <dt-bindings/mux/mux.h>
#define PCA954X_MAX_NCHANS 8
@@ -108,8 +107,6 @@ struct pca954x {
const struct chip_desc *chip;
u8 last_chan; /* last register value */
- /* MUX_IDLE_AS_IS, MUX_IDLE_DISCONNECT or >= 0 for channel */
- s32 idle_state;
struct i2c_client *client;
@@ -337,14 +334,14 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
{
struct pca954x *data = i2c_mux_priv(muxc);
struct i2c_client *client = data->client;
- s32 idle_state;
+ int idle_state;
- idle_state = READ_ONCE(data->idle_state);
+ idle_state = i2c_mux_idle_state(muxc);
if (idle_state >= 0)
/* Set the mux back to a predetermined channel */
return pca954x_select_chan(muxc, idle_state);
- if (idle_state == MUX_IDLE_DISCONNECT) {
+ if (idle_state == I2C_MUX_IDLE_DISCONNECT) {
/* Deselect active channel */
data->last_chan = 0;
return pca954x_reg_write(muxc->parent, client,
@@ -356,15 +353,30 @@ static int pca954x_deselect_mux(struct i2c_mux_core *muxc, u32 chan)
return 0;
}
+/*
+ * The mux core only knows the maximum number of channels the driver may
+ * register, so range-check against the actual channel count of this chip
+ * before handing the state over.
+ */
+static int pca954x_set_idle_state(struct i2c_mux_core *muxc, int state)
+{
+ struct pca954x *data = i2c_mux_priv(muxc);
+
+ /* I2C_MUX_IDLE_UNKNOWN is internal to the mux core. */
+ if (state == I2C_MUX_IDLE_UNKNOWN || state >= data->chip->nchans)
+ return -EINVAL;
+
+ return i2c_mux_set_idle_state(muxc, state);
+}
+
static ssize_t idle_state_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
- struct pca954x *data = i2c_mux_priv(muxc);
- return sprintf(buf, "%d\n", READ_ONCE(data->idle_state));
+ return sprintf(buf, "%d\n", i2c_mux_idle_state(muxc));
}
static ssize_t idle_state_store(struct device *dev,
@@ -381,18 +393,19 @@ static ssize_t idle_state_store(struct device *dev,
if (ret < 0)
return ret;
- if (val != MUX_IDLE_AS_IS && val != MUX_IDLE_DISCONNECT &&
- (val < 0 || val >= data->chip->nchans))
- return -EINVAL;
-
i2c_lock_bus(muxc->parent, I2C_LOCK_SEGMENT);
- WRITE_ONCE(data->idle_state, val);
+ ret = pca954x_set_idle_state(muxc, val);
+ if (ret) {
+ i2c_unlock_bus(muxc->parent, I2C_LOCK_SEGMENT);
+ return ret;
+ }
+
/*
* Set the mux into a state consistent with the new
* idle_state.
*/
- if (data->last_chan || val != MUX_IDLE_DISCONNECT)
+ if (data->last_chan || val != I2C_MUX_IDLE_DISCONNECT)
ret = pca954x_deselect_mux(muxc, 0);
i2c_unlock_bus(muxc->parent, I2C_LOCK_SEGMENT);
@@ -478,12 +491,15 @@ static void pca954x_cleanup(struct i2c_mux_core *muxc)
i2c_mux_del_adapters(muxc);
}
-static int pca954x_init(struct i2c_client *client, struct pca954x *data)
+static int pca954x_init(struct i2c_mux_core *muxc)
{
+ struct pca954x *data = i2c_mux_priv(muxc);
+ struct i2c_client *client = data->client;
+ int idle_state = i2c_mux_idle_state(muxc);
int ret;
- if (data->idle_state >= 0)
- data->last_chan = pca954x_regval(data, data->idle_state);
+ if (idle_state >= 0)
+ data->last_chan = pca954x_regval(data, idle_state);
else
data->last_chan = 0; /* Disconnect multiplexer */
@@ -560,6 +576,8 @@ static int pca954x_probe(struct i2c_client *client)
struct device *dev = &client->dev;
struct i2c_mux_core *muxc;
struct pca954x *data;
+ int idle_state;
+ u32 prop;
int num;
int ret;
@@ -618,25 +636,32 @@ static int pca954x_probe(struct i2c_client *client)
}
}
- data->idle_state = MUX_IDLE_AS_IS;
- if (device_property_read_u32(dev, "idle-state", &data->idle_state)) {
- if (device_property_read_bool(dev, "i2c-mux-idle-disconnect"))
- data->idle_state = MUX_IDLE_DISCONNECT;
- }
-
/*
* Write the mux register at addr to verify
* that the mux is in fact present. This also
* initializes the mux to a channel
* or disconnected state.
*/
- ret = pca954x_init(client, data);
+ ret = pca954x_init(muxc);
if (ret < 0) {
dev_warn(dev, "probe failed\n");
ret = -ENODEV;
goto fail_cleanup;
}
+ /* Set idle state to the default value, or to the value specified in the device tree */
+ idle_state = I2C_MUX_IDLE_AS_IS;
+ if (!device_property_read_u32(dev, "idle-state", &prop))
+ idle_state = (int)prop;
+ else if (device_property_read_bool(dev, "i2c-mux-idle-disconnect"))
+ idle_state = I2C_MUX_IDLE_DISCONNECT;
+
+ ret = pca954x_set_idle_state(muxc, idle_state);
+ if (ret) {
+ dev_err(dev, "invalid idle state %d\n", idle_state);
+ goto fail_cleanup;
+ }
+
ret = pca954x_irq_setup(muxc);
if (ret)
goto fail_cleanup;
@@ -687,10 +712,9 @@ static int pca954x_resume(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
struct i2c_mux_core *muxc = i2c_get_clientdata(client);
- struct pca954x *data = i2c_mux_priv(muxc);
int ret;
- ret = pca954x_init(client, data);
+ ret = pca954x_init(muxc);
if (ret < 0)
dev_err(&client->dev, "failed to verify mux presence\n");
--
2.55.0