drivers/i2c/muxes/i2c-demux-pinctrl.c

Source file repositories/reference/linux-study-clean/drivers/i2c/muxes/i2c-demux-pinctrl.c

File Facts

System
Linux kernel
Corpus path
drivers/i2c/muxes/i2c-demux-pinctrl.c
Extension
.c
Size
8582 bytes
Lines
327
Domain
Driver Families
Bucket
drivers/i2c
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct i2c_demux_pinctrl_chan {
	struct device_node *parent_np;
	struct i2c_adapter *parent_adap;
	struct of_changeset chgset;
};

struct i2c_demux_pinctrl_priv {
	int cur_chan;
	int num_chan;
	struct device *dev;
	const char *bus_name;
	struct i2c_adapter cur_adap;
	struct i2c_algorithm algo;
	struct i2c_demux_pinctrl_chan chan[] __counted_by(num_chan);
};

static int i2c_demux_master_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], int num)
{
	struct i2c_demux_pinctrl_priv *priv = adap->algo_data;
	struct i2c_adapter *parent = priv->chan[priv->cur_chan].parent_adap;

	return __i2c_transfer(parent, msgs, num);
}

static u32 i2c_demux_functionality(struct i2c_adapter *adap)
{
	struct i2c_demux_pinctrl_priv *priv = adap->algo_data;
	struct i2c_adapter *parent = priv->chan[priv->cur_chan].parent_adap;

	return parent->algo->functionality(parent);
}

static int i2c_demux_activate_master(struct i2c_demux_pinctrl_priv *priv, u32 new_chan)
{
	struct i2c_adapter *adap;
	struct pinctrl *p;
	int ret;

	ret = of_changeset_apply(&priv->chan[new_chan].chgset);
	if (ret)
		goto err;

	adap = of_get_i2c_adapter_by_node(priv->chan[new_chan].parent_np);
	if (!adap) {
		ret = -ENODEV;
		goto err_with_revert;
	}

	/*
	 * Check if there are pinctrl states at all. Note: we can't use
	 * devm_pinctrl_get_select() because we need to distinguish between
	 * the -ENODEV from devm_pinctrl_get() and pinctrl_lookup_state().
	 */
	p = devm_pinctrl_get(adap->dev.parent);
	if (IS_ERR(p)) {
		ret = PTR_ERR(p);
		/* continue if just no pinctrl states (e.g. i2c-gpio), otherwise exit */
		if (ret != -ENODEV)
			goto err_with_put;
	} else {
		/* there are states. check and use them */
		struct pinctrl_state *s = pinctrl_lookup_state(p, priv->bus_name);

		if (IS_ERR(s)) {
			ret = PTR_ERR(s);
			goto err_with_put;
		}
		ret = pinctrl_select_state(p, s);
		if (ret < 0)
			goto err_with_put;
	}

	priv->chan[new_chan].parent_adap = adap;
	priv->cur_chan = new_chan;

	/* Now fill out current adapter structure. cur_chan must be up to date */
	priv->algo.xfer = i2c_demux_master_xfer;
	if (adap->algo->master_xfer_atomic)
		priv->algo.xfer_atomic = i2c_demux_master_xfer;
	priv->algo.functionality = i2c_demux_functionality;

	snprintf(priv->cur_adap.name, sizeof(priv->cur_adap.name),
		 "i2c-demux (master i2c-%d)", i2c_adapter_id(adap));
	priv->cur_adap.owner = THIS_MODULE;
	priv->cur_adap.algo = &priv->algo;
	priv->cur_adap.algo_data = priv;
	priv->cur_adap.dev.parent = &adap->dev;
	priv->cur_adap.class = adap->class;
	priv->cur_adap.retries = adap->retries;
	priv->cur_adap.timeout = adap->timeout;

Annotation

Implementation Notes