diff mbox series

[RFC,v3,3/4] mux: Add support for reading mux enable state from DT

Message ID 20211123081222.27979-4-a-govindraju@ti.com
State RFC
Headers show
Series MUX: Add support for reading enable state from DT | expand

Commit Message

Aswath Govindraju Nov. 23, 2021, 8:12 a.m. UTC
In some cases, we might need to provide the state of the mux to be set for
the operation of a given peripheral. Therefore, pass this information using
the second argument of the mux-controls property.

Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
---
 drivers/mux/core.c           | 146 ++++++++++++++++++++++++++++++++++-
 include/linux/mux/consumer.h |  19 ++++-
 include/linux/mux/driver.h   |  13 ++++
 3 files changed, 173 insertions(+), 5 deletions(-)

Comments

Peter Rosin Nov. 25, 2021, 1:52 p.m. UTC | #1
Hi!

On 2021-11-23 09:12, Aswath Govindraju wrote:
> In some cases, we might need to provide the state of the mux to be set for
> the operation of a given peripheral. Therefore, pass this information using
> the second argument of the mux-controls property.
> 
> Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
> ---
>  drivers/mux/core.c           | 146 ++++++++++++++++++++++++++++++++++-
>  include/linux/mux/consumer.h |  19 ++++-
>  include/linux/mux/driver.h   |  13 ++++
>  3 files changed, 173 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/mux/core.c b/drivers/mux/core.c
> index 22f4709768d1..9622b98f9818 100644
> --- a/drivers/mux/core.c
> +++ b/drivers/mux/core.c
> @@ -370,6 +370,29 @@ int mux_control_select_delay(struct mux_control *mux, unsigned int state,
>  }
>  EXPORT_SYMBOL_GPL(mux_control_select_delay);
>  
> +/**
> + * mux_state_select_delay() - Select the enable state in mux-state

The terminology is that you have a "mux" with different "states" that you
"select". What you are referring to as enabling a mux state, is elsewhere
referred to as selecting the mux state.

> + * @mux: The mux-state to request a change of state from.
> + * @delay_us: The time to delay (in microseconds) if the mux state is changed.
> + *
> + * On successfully selecting the enable state, it will be locked until
> + * there is a call to mux_state_deselect(). If the mux-control is already
> + * selected when mux_state_select() is called, the caller will be blocked
> + * until mux_state_deselect() is called (by someone else).
> + *
> + * Therefore, make sure to call mux_state_deselect() when the operation is
> + * complete and the mux-control is free for others to use, but do not call
> + * mux_state_deselect() if mux_state_select() fails.
> + *
> + * Return: 0 when the mux-state has the enable state or a negative
> + * errno on error.
> + */
> +int mux_state_select_delay(struct mux_state *mux, unsigned int delay_us)

I dislike the name "mux" here, that name is consistently referring to
a struct mux-control in the mux subsystem. If mux_state is too long,
maybe mstate or something such, just not plain mux. That goes for all
the struct mux_state variables that follow too. I.e. pick a new name
for variables of this type and stick to it (unless you need more than
one such variable in a context, of course).

> +{
> +	return mux_control_select_delay(mux->mux, mux->enable_state, delay_us);
> +}
> +EXPORT_SYMBOL_GPL(mux_state_select_delay);

Taking the above into account, I would like to see:

/**
 * mux_state_select_delay() - Select the mux-state
 * @mstate: The mux-state to select.
 * @delay_us: The time to delay (in microseconds) if the mux-control changes
 *            state on select.
 *
 * On successfully selecting the mux-state, its mux-control will be locked
 * until there is a call to mux_state_deselect(). If the mux-control is
 * already selected when mux_state_select() is called, the caller will be
 * blocked until the mux-control is deselected (by someone else).
 *
 * Therefore, make sure to call mux_state_deselect() when the operation is
 * complete and the mux-control is free for others to use, but do not call
 * mux_state_deselect() if mux_state_select() fails.
 *
 * Return: 0 when the mux-state has been selected or a negative errno on
 * error.
 */
int mux_state_select_delay(struct mux_state *mstate, unsigned int delay_us)

And then similar changes for the other new mux_state_ functions.

> +
>  /**
>   * mux_control_try_select_delay() - Try to select the given multiplexer state.
>   * @mux: The mux-control to request a change of state from.
> @@ -405,6 +428,27 @@ int mux_control_try_select_delay(struct mux_control *mux, unsigned int state,
>  }
>  EXPORT_SYMBOL_GPL(mux_control_try_select_delay);
>  
> +/**
> + * mux_state_try_select_delay() - Try to select the multiplexer enable state.
> + * @mux: The mux-control to request a change of state from.
> + * @delay_us: The time to delay (in microseconds) if the mux state is changed.
> + *
> + * On successfully selecting the enable state, it will be locked until
> + * mux_state_deselect() called.
> + *
> + * Therefore, make sure to call mux_state_deselect() when the operation is
> + * complete and the mux-control is free for others to use, but do not call
> + * mux_state_deselect() if mux_state_try_select() fails.
> + *
> + * Return: 0 when the mux-control state has the requested state or a negative
> + * errno on error. Specifically -EBUSY if the mux-control is contended.
> + */
> +int mux_state_try_select_delay(struct mux_state *mux, unsigned int delay_us)
> +{
> +	return mux_control_try_select_delay(mux->mux, mux->enable_state, delay_us);
> +}
> +EXPORT_SYMBOL_GPL(mux_state_try_select_delay);
> +
>  /**
>   * mux_control_deselect() - Deselect the previously selected multiplexer state.
>   * @mux: The mux-control to deselect.
> @@ -431,6 +475,24 @@ int mux_control_deselect(struct mux_control *mux)
>  }
>  EXPORT_SYMBOL_GPL(mux_control_deselect);
>  
> +/**
> + * mux_state_deselect() - Deselect the previously selected multiplexer state.
> + * @mux: The mux-state to deselect.
> + *
> + * It is required that a single call is made to mux_state_deselect() for
> + * each and every successful call made to either of mux_state_select() or
> + * mux_state_try_select().
> + *
> + * Return: 0 on success and a negative errno on error. An error can only
> + * occur if the mux has an idle state. Note that even if an error occurs, the
> + * mux-control is unlocked and is thus free for the next access.
> + */
> +int mux_state_deselect(struct mux_state *mux)
> +{
> +	return mux_control_deselect(mux->mux);
> +}
> +EXPORT_SYMBOL_GPL(mux_state_deselect);
> +
>  /* Note this function returns a reference to the mux_chip dev. */
>  static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
>  {
> @@ -442,13 +504,15 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
>  }
>  
>  /**
> - * mux_control_get() - Get the mux-control for a device.
> + * mux_get() - Get the mux-control for a device.
>   * @dev: The device that needs a mux-control.
>   * @mux_name: The name identifying the mux-control.
> + * @enable_state: The variable to store the enable state for the requested device
>   *
>   * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
>   */
> -struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
> +static struct mux_control *mux_get(struct device *dev, const char *mux_name,
> +				   unsigned int *enable_state)

s/enable_state/state/ (goes for all of the patch).

>  {
>  	struct device_node *np = dev->of_node;
>  	struct of_phandle_args args;
> @@ -481,8 +545,7 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>  	if (!mux_chip)
>  		return ERR_PTR(-EPROBE_DEFER);
>  
> -	if (args.args_count > 1 ||

It is inconsistent to allow more than 2 args, but then only allow
digging out the state from the 2nd arg if the count is exactly 2.

> -	    (!args.args_count && (mux_chip->controllers > 1))) {
> +	if (!args.args_count && mux_chip->controllers > 1) {
>  		dev_err(dev, "%pOF: wrong #mux-control-cells for %pOF\n",
>  			np, args.np);
>  		put_device(&mux_chip->dev);
> @@ -500,8 +563,25 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>  		return ERR_PTR(-EINVAL);
>  	}
>  
> +	if (args.args_count == 2)
> +		*enable_state = args.args[1];
> +

With the suggested binding in my comment for patch 1/4, you'd need to do
either

	ret = of_parse_phandle_with_args(np,
					 "mux-controls", "#mux-control-cells",
					 index, &args);

or

	ret = of_parse_phandle_with_args(np,
					 "mux-states", "#mux-state-cells",
					 index, &args);

depending on if the mux_get helper gets a NULL (enable_)state pointer or a "real"
address, and then...

>  	return &mux_chip->mux[controller];
>  }
> +
> +/**
> + * mux_control_get() - Get the mux-control for a device.
> + * @dev: The device that needs a mux-control.
> + * @mux_name: The name identifying the mux-control.
> + *
> + * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
> + */
> +struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
> +{
> +	int state;
> +
> +	return mux_get(dev, mux_name, &state);

...pass NULL as the 3rd arg here.

> +}
>  EXPORT_SYMBOL_GPL(mux_control_get);
>  
>  /**
> @@ -523,6 +603,26 @@ static void devm_mux_control_release(struct device *dev, void *res)
>  	mux_control_put(mux);
>  }
>  
> +/**
> + * mux_state_put() - Put away the mux-state for good.
> + * @mux: The mux-state to put away.
> + *
> + * mux_control_put() reverses the effects of mux_control_get().
> + */
> +void mux_state_put(struct mux_state *mux_state)
> +{
> +	mux_control_put(mux_state->mux);
> +	kfree(mux_state);
> +}
> +EXPORT_SYMBOL_GPL(mux_state_put);
> +
> +static void devm_mux_state_release(struct device *dev, void *res)
> +{
> +	struct mux_state *mux = *(struct mux_state **)res;
> +
> +	mux_state_put(mux);
> +}
> +
>  /**
>   * devm_mux_control_get() - Get the mux-control for a device, with resource
>   *			    management.
> @@ -553,6 +653,44 @@ struct mux_control *devm_mux_control_get(struct device *dev,
>  }
>  EXPORT_SYMBOL_GPL(devm_mux_control_get);
>  
> +/**
> + * devm_mux_state_get() - Get the mux-state for a device, with resource
> + *			  management.
> + * @dev: The device that needs a mux-control.
> + * @mux_name: The name identifying the mux-control.
> + *
> + * Return: Pointer to the mux-state, or an ERR_PTR with a negative errno.
> + */
> +struct mux_state *devm_mux_state_get(struct device *dev,
> +				     const char *mux_name)
> +{
> +	struct mux_state **ptr, *mux_state;
> +	struct mux_control *mux_ctrl;
> +	int enable_state;
> +
> +	mux_state = devm_kzalloc(dev, sizeof(struct mux_state), GFP_KERNEL);
> +	if (!mux_state)
> +		return ERR_PTR(-ENOMEM);
> +
> +	ptr = devres_alloc(devm_mux_state_release, sizeof(*ptr), GFP_KERNEL);
> +	if (!ptr)
> +		return ERR_PTR(-ENOMEM);
> +
> +	mux_ctrl = mux_get(dev, mux_name, &enable_state);
> +	if (IS_ERR(mux_ctrl)) {
> +		devres_free(ptr);
> +		return (struct mux_state *)mux_ctrl;
> +	}
> +
> +	mux_state->mux = mux_ctrl;
> +	mux_state->enable_state = enable_state;
> +	*ptr = mux_state;
> +	devres_add(dev, ptr);
> +
> +	return mux_state;
> +}
> +EXPORT_SYMBOL_GPL(devm_mux_state_get);
> +
>  /*
>   * Using subsys_initcall instead of module_init here to try to ensure - for
>   * the non-modular case - that the subsystem is initialized when mux consumers
> diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
> index 7a09b040ac39..d0f3242e148d 100644
> --- a/include/linux/mux/consumer.h
> +++ b/include/linux/mux/consumer.h
> @@ -14,33 +14,50 @@
>  
>  struct device;
>  struct mux_control;
> +struct mux_state;
>  
>  unsigned int mux_control_states(struct mux_control *mux);
>  int __must_check mux_control_select_delay(struct mux_control *mux,
>  					  unsigned int state,
>  					  unsigned int delay_us);
> +int __must_check mux_state_select_delay(struct mux_state *mux,
> +					unsigned int delay_us);
>  int __must_check mux_control_try_select_delay(struct mux_control *mux,
>  					      unsigned int state,
>  					      unsigned int delay_us);
> -
> +int __must_check mux_state_try_select_delay(struct mux_state *mux,
> +					    unsigned int delay_us);
>  static inline int __must_check mux_control_select(struct mux_control *mux,
>  						  unsigned int state)
>  {
>  	return mux_control_select_delay(mux, state, 0);
>  }
>  
> +static inline int __must_check mux_state_select(struct mux_state *mux)
> +{
> +	return mux_state_select_delay(mux, 0);
> +}
>  static inline int __must_check mux_control_try_select(struct mux_control *mux,
>  						      unsigned int state)
>  {
>  	return mux_control_try_select_delay(mux, state, 0);
>  }
>  
> +static inline int __must_check mux_state_try_select(struct mux_state *mux)
> +{
> +	return mux_state_try_select_delay(mux, 0);
> +}
> +
>  int mux_control_deselect(struct mux_control *mux);
> +int mux_state_deselect(struct mux_state *mux);
>  
>  struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
>  void mux_control_put(struct mux_control *mux);
> +void mux_state_put(struct mux_state *mux);
>  
>  struct mux_control *devm_mux_control_get(struct device *dev,
>  					 const char *mux_name);
> +struct mux_state *devm_mux_state_get(struct device *dev,
> +				     const char *mux_name);
>  
>  #endif /* _LINUX_MUX_CONSUMER_H */
> diff --git a/include/linux/mux/driver.h b/include/linux/mux/driver.h
> index 18824064f8c0..c7236f307fbd 100644
> --- a/include/linux/mux/driver.h
> +++ b/include/linux/mux/driver.h
> @@ -53,6 +53,19 @@ struct mux_control {
>  	ktime_t last_change;
>  };
>  
> +/**
> + * struct mux_state -	Represents a mux controller specific to a given device
> + * @mux:		Pointer to a mux controller
> + * @enable_state	State of the mux to be set for enabling a device
> + *
> + * This structure is specific to a device that acquires it and has information
> + * specific to the device.
> + */
> +struct mux_state {
> +	struct mux_control *mux;
> +	unsigned int enable_state;
> +};
> +
>  /**
>   * struct mux_chip -	Represents a chip holding mux controllers.
>   * @controllers:	Number of mux controllers handled by the chip.
> 

This struct does not belong in driver.h, as it's purely a consumer thing.
That said, it need not be in consumer.h either, as there is no need to
"expose" the struct guts in any header. Just add it directly in core.c
which is the only file that digs around in the struct.

Cheers,
Peter
Aswath Govindraju Nov. 29, 2021, 4:44 a.m. UTC | #2
Hi Peter,

On 25/11/21 7:22 pm, Peter Rosin wrote:
> Hi!
> 
> On 2021-11-23 09:12, Aswath Govindraju wrote:
>> In some cases, we might need to provide the state of the mux to be set for
>> the operation of a given peripheral. Therefore, pass this information using
>> the second argument of the mux-controls property.
>>
>> Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
>> ---
>>  drivers/mux/core.c           | 146 ++++++++++++++++++++++++++++++++++-
>>  include/linux/mux/consumer.h |  19 ++++-
>>  include/linux/mux/driver.h   |  13 ++++
>>  3 files changed, 173 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/mux/core.c b/drivers/mux/core.c
>> index 22f4709768d1..9622b98f9818 100644
>> --- a/drivers/mux/core.c
>> +++ b/drivers/mux/core.c
>> @@ -370,6 +370,29 @@ int mux_control_select_delay(struct mux_control *mux, unsigned int state,
>>  }
>>  EXPORT_SYMBOL_GPL(mux_control_select_delay);
>>  
>> +/**
>> + * mux_state_select_delay() - Select the enable state in mux-state
> 
> The terminology is that you have a "mux" with different "states" that you
> "select". What you are referring to as enabling a mux state, is elsewhere
> referred to as selecting the mux state.
> 

Sorry, for mentioning what I mean by enable state. So, the idea is the
the state that would be mentioned in the DT property would be the state
to which the mux to be set for enabling the given device and hence I am
referring to it as enable state. I feel that referring to it as state
would not convey the above.

>> + * @mux: The mux-state to request a change of state from.
>> + * @delay_us: The time to delay (in microseconds) if the mux state is changed.
>> + *
>> + * On successfully selecting the enable state, it will be locked until
>> + * there is a call to mux_state_deselect(). If the mux-control is already
>> + * selected when mux_state_select() is called, the caller will be blocked
>> + * until mux_state_deselect() is called (by someone else).
>> + *
>> + * Therefore, make sure to call mux_state_deselect() when the operation is
>> + * complete and the mux-control is free for others to use, but do not call
>> + * mux_state_deselect() if mux_state_select() fails.
>> + *
>> + * Return: 0 when the mux-state has the enable state or a negative
>> + * errno on error.
>> + */
>> +int mux_state_select_delay(struct mux_state *mux, unsigned int delay_us)
> 
> I dislike the name "mux" here, that name is consistently referring to
> a struct mux-control in the mux subsystem. If mux_state is too long,
> maybe mstate or something such, just not plain mux. That goes for all
> the struct mux_state variables that follow too. I.e. pick a new name
> for variables of this type and stick to it (unless you need more than
> one such variable in a context, of course).
> 

Yes, using mux for mux_state type does seem to be misleading. I'll
change it to the mstate.

Thanks,
Aswath

>> +{
>> +	return mux_control_select_delay(mux->mux, mux->enable_state, delay_us);
>> +}
>> +EXPORT_SYMBOL_GPL(mux_state_select_delay);
> 
> Taking the above into account, I would like to see:
> 
> /**
>  * mux_state_select_delay() - Select the mux-state
>  * @mstate: The mux-state to select.
>  * @delay_us: The time to delay (in microseconds) if the mux-control changes
>  *            state on select.
>  *
>  * On successfully selecting the mux-state, its mux-control will be locked
>  * until there is a call to mux_state_deselect(). If the mux-control is
>  * already selected when mux_state_select() is called, the caller will be
>  * blocked until the mux-control is deselected (by someone else).
>  *
>  * Therefore, make sure to call mux_state_deselect() when the operation is
>  * complete and the mux-control is free for others to use, but do not call
>  * mux_state_deselect() if mux_state_select() fails.
>  *
>  * Return: 0 when the mux-state has been selected or a negative errno on
>  * error.
>  */
> int mux_state_select_delay(struct mux_state *mstate, unsigned int delay_us)
> 
> And then similar changes for the other new mux_state_ functions.
> 
>> +
>>  /**
>>   * mux_control_try_select_delay() - Try to select the given multiplexer state.
>>   * @mux: The mux-control to request a change of state from.
>> @@ -405,6 +428,27 @@ int mux_control_try_select_delay(struct mux_control *mux, unsigned int state,
>>  }
>>  EXPORT_SYMBOL_GPL(mux_control_try_select_delay);
>>  
>> +/**
>> + * mux_state_try_select_delay() - Try to select the multiplexer enable state.
>> + * @mux: The mux-control to request a change of state from.
>> + * @delay_us: The time to delay (in microseconds) if the mux state is changed.
>> + *
>> + * On successfully selecting the enable state, it will be locked until
>> + * mux_state_deselect() called.
>> + *
>> + * Therefore, make sure to call mux_state_deselect() when the operation is
>> + * complete and the mux-control is free for others to use, but do not call
>> + * mux_state_deselect() if mux_state_try_select() fails.
>> + *
>> + * Return: 0 when the mux-control state has the requested state or a negative
>> + * errno on error. Specifically -EBUSY if the mux-control is contended.
>> + */
>> +int mux_state_try_select_delay(struct mux_state *mux, unsigned int delay_us)
>> +{
>> +	return mux_control_try_select_delay(mux->mux, mux->enable_state, delay_us);
>> +}
>> +EXPORT_SYMBOL_GPL(mux_state_try_select_delay);
>> +
>>  /**
>>   * mux_control_deselect() - Deselect the previously selected multiplexer state.
>>   * @mux: The mux-control to deselect.
>> @@ -431,6 +475,24 @@ int mux_control_deselect(struct mux_control *mux)
>>  }
>>  EXPORT_SYMBOL_GPL(mux_control_deselect);
>>  
>> +/**
>> + * mux_state_deselect() - Deselect the previously selected multiplexer state.
>> + * @mux: The mux-state to deselect.
>> + *
>> + * It is required that a single call is made to mux_state_deselect() for
>> + * each and every successful call made to either of mux_state_select() or
>> + * mux_state_try_select().
>> + *
>> + * Return: 0 on success and a negative errno on error. An error can only
>> + * occur if the mux has an idle state. Note that even if an error occurs, the
>> + * mux-control is unlocked and is thus free for the next access.
>> + */
>> +int mux_state_deselect(struct mux_state *mux)
>> +{
>> +	return mux_control_deselect(mux->mux);
>> +}
>> +EXPORT_SYMBOL_GPL(mux_state_deselect);
>> +
>>  /* Note this function returns a reference to the mux_chip dev. */
>>  static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
>>  {
>> @@ -442,13 +504,15 @@ static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
>>  }
>>  
>>  /**
>> - * mux_control_get() - Get the mux-control for a device.
>> + * mux_get() - Get the mux-control for a device.
>>   * @dev: The device that needs a mux-control.
>>   * @mux_name: The name identifying the mux-control.
>> + * @enable_state: The variable to store the enable state for the requested device
>>   *
>>   * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
>>   */
>> -struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>> +static struct mux_control *mux_get(struct device *dev, const char *mux_name,
>> +				   unsigned int *enable_state)
> 
> s/enable_state/state/ (goes for all of the patch).
> 
>>  {
>>  	struct device_node *np = dev->of_node;
>>  	struct of_phandle_args args;
>> @@ -481,8 +545,7 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>>  	if (!mux_chip)
>>  		return ERR_PTR(-EPROBE_DEFER);
>>  
>> -	if (args.args_count > 1 ||
> 
> It is inconsistent to allow more than 2 args, but then only allow
> digging out the state from the 2nd arg if the count is exactly 2.
> 
>> -	    (!args.args_count && (mux_chip->controllers > 1))) {
>> +	if (!args.args_count && mux_chip->controllers > 1) {
>>  		dev_err(dev, "%pOF: wrong #mux-control-cells for %pOF\n",
>>  			np, args.np);
>>  		put_device(&mux_chip->dev);
>> @@ -500,8 +563,25 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>>  		return ERR_PTR(-EINVAL);
>>  	}
>>  
>> +	if (args.args_count == 2)
>> +		*enable_state = args.args[1];
>> +
> 
> With the suggested binding in my comment for patch 1/4, you'd need to do
> either
> 
> 	ret = of_parse_phandle_with_args(np,
> 					 "mux-controls", "#mux-control-cells",
> 					 index, &args);
> 
> or
> 
> 	ret = of_parse_phandle_with_args(np,
> 					 "mux-states", "#mux-state-cells",
> 					 index, &args);
> 
> depending on if the mux_get helper gets a NULL (enable_)state pointer or a "real"
> address, and then...
> 
>>  	return &mux_chip->mux[controller];
>>  }
>> +
>> +/**
>> + * mux_control_get() - Get the mux-control for a device.
>> + * @dev: The device that needs a mux-control.
>> + * @mux_name: The name identifying the mux-control.
>> + *
>> + * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
>> + */
>> +struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>> +{
>> +	int state;
>> +
>> +	return mux_get(dev, mux_name, &state);
> 
> ...pass NULL as the 3rd arg here.
> 
>> +}
>>  EXPORT_SYMBOL_GPL(mux_control_get);
>>  
>>  /**
>> @@ -523,6 +603,26 @@ static void devm_mux_control_release(struct device *dev, void *res)
>>  	mux_control_put(mux);
>>  }
>>  
>> +/**
>> + * mux_state_put() - Put away the mux-state for good.
>> + * @mux: The mux-state to put away.
>> + *
>> + * mux_control_put() reverses the effects of mux_control_get().
>> + */
>> +void mux_state_put(struct mux_state *mux_state)
>> +{
>> +	mux_control_put(mux_state->mux);
>> +	kfree(mux_state);
>> +}
>> +EXPORT_SYMBOL_GPL(mux_state_put);
>> +
>> +static void devm_mux_state_release(struct device *dev, void *res)
>> +{
>> +	struct mux_state *mux = *(struct mux_state **)res;
>> +
>> +	mux_state_put(mux);
>> +}
>> +
>>  /**
>>   * devm_mux_control_get() - Get the mux-control for a device, with resource
>>   *			    management.
>> @@ -553,6 +653,44 @@ struct mux_control *devm_mux_control_get(struct device *dev,
>>  }
>>  EXPORT_SYMBOL_GPL(devm_mux_control_get);
>>  
>> +/**
>> + * devm_mux_state_get() - Get the mux-state for a device, with resource
>> + *			  management.
>> + * @dev: The device that needs a mux-control.
>> + * @mux_name: The name identifying the mux-control.
>> + *
>> + * Return: Pointer to the mux-state, or an ERR_PTR with a negative errno.
>> + */
>> +struct mux_state *devm_mux_state_get(struct device *dev,
>> +				     const char *mux_name)
>> +{
>> +	struct mux_state **ptr, *mux_state;
>> +	struct mux_control *mux_ctrl;
>> +	int enable_state;
>> +
>> +	mux_state = devm_kzalloc(dev, sizeof(struct mux_state), GFP_KERNEL);
>> +	if (!mux_state)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	ptr = devres_alloc(devm_mux_state_release, sizeof(*ptr), GFP_KERNEL);
>> +	if (!ptr)
>> +		return ERR_PTR(-ENOMEM);
>> +
>> +	mux_ctrl = mux_get(dev, mux_name, &enable_state);
>> +	if (IS_ERR(mux_ctrl)) {
>> +		devres_free(ptr);
>> +		return (struct mux_state *)mux_ctrl;
>> +	}
>> +
>> +	mux_state->mux = mux_ctrl;
>> +	mux_state->enable_state = enable_state;
>> +	*ptr = mux_state;
>> +	devres_add(dev, ptr);
>> +
>> +	return mux_state;
>> +}
>> +EXPORT_SYMBOL_GPL(devm_mux_state_get);
>> +
>>  /*
>>   * Using subsys_initcall instead of module_init here to try to ensure - for
>>   * the non-modular case - that the subsystem is initialized when mux consumers
>> diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
>> index 7a09b040ac39..d0f3242e148d 100644
>> --- a/include/linux/mux/consumer.h
>> +++ b/include/linux/mux/consumer.h
>> @@ -14,33 +14,50 @@
>>  
>>  struct device;
>>  struct mux_control;
>> +struct mux_state;
>>  
>>  unsigned int mux_control_states(struct mux_control *mux);
>>  int __must_check mux_control_select_delay(struct mux_control *mux,
>>  					  unsigned int state,
>>  					  unsigned int delay_us);
>> +int __must_check mux_state_select_delay(struct mux_state *mux,
>> +					unsigned int delay_us);
>>  int __must_check mux_control_try_select_delay(struct mux_control *mux,
>>  					      unsigned int state,
>>  					      unsigned int delay_us);
>> -
>> +int __must_check mux_state_try_select_delay(struct mux_state *mux,
>> +					    unsigned int delay_us);
>>  static inline int __must_check mux_control_select(struct mux_control *mux,
>>  						  unsigned int state)
>>  {
>>  	return mux_control_select_delay(mux, state, 0);
>>  }
>>  
>> +static inline int __must_check mux_state_select(struct mux_state *mux)
>> +{
>> +	return mux_state_select_delay(mux, 0);
>> +}
>>  static inline int __must_check mux_control_try_select(struct mux_control *mux,
>>  						      unsigned int state)
>>  {
>>  	return mux_control_try_select_delay(mux, state, 0);
>>  }
>>  
>> +static inline int __must_check mux_state_try_select(struct mux_state *mux)
>> +{
>> +	return mux_state_try_select_delay(mux, 0);
>> +}
>> +
>>  int mux_control_deselect(struct mux_control *mux);
>> +int mux_state_deselect(struct mux_state *mux);
>>  
>>  struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
>>  void mux_control_put(struct mux_control *mux);
>> +void mux_state_put(struct mux_state *mux);
>>  
>>  struct mux_control *devm_mux_control_get(struct device *dev,
>>  					 const char *mux_name);
>> +struct mux_state *devm_mux_state_get(struct device *dev,
>> +				     const char *mux_name);
>>  
>>  #endif /* _LINUX_MUX_CONSUMER_H */
>> diff --git a/include/linux/mux/driver.h b/include/linux/mux/driver.h
>> index 18824064f8c0..c7236f307fbd 100644
>> --- a/include/linux/mux/driver.h
>> +++ b/include/linux/mux/driver.h
>> @@ -53,6 +53,19 @@ struct mux_control {
>>  	ktime_t last_change;
>>  };
>>  
>> +/**
>> + * struct mux_state -	Represents a mux controller specific to a given device
>> + * @mux:		Pointer to a mux controller
>> + * @enable_state	State of the mux to be set for enabling a device
>> + *
>> + * This structure is specific to a device that acquires it and has information
>> + * specific to the device.
>> + */
>> +struct mux_state {
>> +	struct mux_control *mux;
>> +	unsigned int enable_state;
>> +};
>> +
>>  /**
>>   * struct mux_chip -	Represents a chip holding mux controllers.
>>   * @controllers:	Number of mux controllers handled by the chip.
>>
> 
> This struct does not belong in driver.h, as it's purely a consumer thing.
> That said, it need not be in consumer.h either, as there is no need to
> "expose" the struct guts in any header. Just add it directly in core.c
> which is the only file that digs around in the struct.
> 
> Cheers,
> Peter
>
Peter Rosin Nov. 29, 2021, 8:36 a.m. UTC | #3
On 2021-11-29 05:44, Aswath Govindraju wrote:
> Hi Peter,
> 
> On 25/11/21 7:22 pm, Peter Rosin wrote:
>> Hi!
>>
>> On 2021-11-23 09:12, Aswath Govindraju wrote:
>>> In some cases, we might need to provide the state of the mux to be set for
>>> the operation of a given peripheral. Therefore, pass this information using
>>> the second argument of the mux-controls property.
>>>
>>> Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
>>> ---
>>>  drivers/mux/core.c           | 146 ++++++++++++++++++++++++++++++++++-
>>>  include/linux/mux/consumer.h |  19 ++++-
>>>  include/linux/mux/driver.h   |  13 ++++
>>>  3 files changed, 173 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/mux/core.c b/drivers/mux/core.c
>>> index 22f4709768d1..9622b98f9818 100644
>>> --- a/drivers/mux/core.c
>>> +++ b/drivers/mux/core.c
>>> @@ -370,6 +370,29 @@ int mux_control_select_delay(struct mux_control *mux, unsigned int state,
>>>  }
>>>  EXPORT_SYMBOL_GPL(mux_control_select_delay);
>>>  
>>> +/**
>>> + * mux_state_select_delay() - Select the enable state in mux-state
>>
>> The terminology is that you have a "mux" with different "states" that you
>> "select". What you are referring to as enabling a mux state, is elsewhere
>> referred to as selecting the mux state.
>>
> 
> Sorry, for mentioning what I mean by enable state. So, the idea is the
> the state that would be mentioned in the DT property would be the state
> to which the mux to be set for enabling the given device and hence I am
> referring to it as enable state. I feel that referring to it as state
> would not convey the above.

Ah, but that this state it is use to "enable" your device is a mux
consumer detail in the context of the phy-can driver. Some other
driver might need a specific mux state for something completely
unrelated. So, the "enable" naming should not spread into the mux
code.

The situation is similar to when a driver needs an enable-gpio, the
gpio consumer knows that it's a gpio used to enable the device (or
whatever), but the gpio subsystem does not bother at all with what
the gpio is used for.

Cheers,
Peter
Aswath Govindraju Nov. 30, 2021, 5:44 a.m. UTC | #4
Hi Peter,

On 25/11/21 7:22 pm, Peter Rosin wrote:
> Hi!
> 
> On 2021-11-23 09:12, Aswath Govindraju wrote:
>> In some cases, we might need to provide the state of the mux to be set for
>> the operation of a given peripheral. Therefore, pass this information using
>> the second argument of the mux-controls property.
>>
>> Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
>> ---
>>  drivers/mux/core.c           | 146 ++++++++++++++++++++++++++++++++++-
>>  include/linux/mux/consumer.h |  19 ++++-
>>  include/linux/mux/driver.h   |  13 ++++
>>  3 files changed, 173 insertions(+), 5 deletions(-)
>>
>> diff --git a/drivers/mux/core.c b/drivers/mux/core.c
>> index 22f4709768d1..9622b98f9818 100644
>> --- a/drivers/mux/core.c
>> +++ b/drivers/mux/core.c
>> @@ -370,6 +370,29 @@ int mux_control_select_delay(struct mux_control *mux, unsigned int state,
>>  }
>>  EXPORT_SYMBOL_GPL(mux_control_select_delay);
>>  

[...]

>>  }
>>  
>>  /**
>> - * mux_control_get() - Get the mux-control for a device.
>> + * mux_get() - Get the mux-control for a device.
>>   * @dev: The device that needs a mux-control.
>>   * @mux_name: The name identifying the mux-control.
>> + * @enable_state: The variable to store the enable state for the requested device
>>   *
>>   * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
>>   */
>> -struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>> +static struct mux_control *mux_get(struct device *dev, const char *mux_name,
>> +				   unsigned int *enable_state)
> 
> s/enable_state/state/ (goes for all of the patch).
> 
>>  {
>>  	struct device_node *np = dev->of_node;
>>  	struct of_phandle_args args;
>> @@ -481,8 +545,7 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>>  	if (!mux_chip)
>>  		return ERR_PTR(-EPROBE_DEFER);
>>  
>> -	if (args.args_count > 1 ||
> 
> It is inconsistent to allow more than 2 args, but then only allow
> digging out the state from the 2nd arg if the count is exactly 2.
> 
>> -	    (!args.args_count && (mux_chip->controllers > 1))) {
>> +	if (!args.args_count && mux_chip->controllers > 1) {
>>  		dev_err(dev, "%pOF: wrong #mux-control-cells for %pOF\n",
>>  			np, args.np);
>>  		put_device(&mux_chip->dev);
>> @@ -500,8 +563,25 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>>  		return ERR_PTR(-EINVAL);
>>  	}
>>  
>> +	if (args.args_count == 2)
>> +		*enable_state = args.args[1];
>> +
> 
> With the suggested binding in my comment for patch 1/4, you'd need to do
> either
> 
> 	ret = of_parse_phandle_with_args(np,
> 					 "mux-controls", "#mux-control-cells",
> 					 index, &args);
> 
> or
> 
> 	ret = of_parse_phandle_with_args(np,
> 					 "mux-states", "#mux-state-cells",
> 					 index, &args);
> 
> depending on if the mux_get helper gets a NULL (enable_)state pointer or a "real"
> address, and then...
> 


Sorry, while trying to implement the above method, I came across one
more question. So, in a given consumer DT node we will be either having
only mux-states or mux-controls right? How would we take care of the
condition when we would want to set the state of a given line in the
controller. Especially when a single mux chip is used by multiple
consumers each using a different line. Wouldn't we require both
mux-controls and mux-states in that case? So, shouldn't the
implementation be such that we need to first read mux-controls and then
based whether the enable_state is NULL, we read mux-states?

Just to add more clarity, if we go about this method then we would have
both mux-controls and mux-states in the consumer DT node when we want to
specify the state.

Thanks,
Aswath

>>  	return &mux_chip->mux[controller];
>>  }
>> +
>> +/**
>> + * mux_control_get() - Get the mux-control for a device.
>> + * @dev: The device that needs a mux-control.
>> + * @mux_name: The name identifying the mux-control.
>> + *
>> + * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
>> + */
>> +struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>> +{

[...]
Aswath Govindraju Nov. 30, 2021, 5:58 a.m. UTC | #5
Hi Peter,

On 30/11/21 11:14 am, Aswath Govindraju wrote:
> Hi Peter,
> 
> On 25/11/21 7:22 pm, Peter Rosin wrote:
>> Hi!
>>
>> On 2021-11-23 09:12, Aswath Govindraju wrote:
>>> In some cases, we might need to provide the state of the mux to be set for
>>> the operation of a given peripheral. Therefore, pass this information using
>>> the second argument of the mux-controls property.
>>>
>>> Signed-off-by: Aswath Govindraju <a-govindraju@ti.com>
>>> ---
>>>  drivers/mux/core.c           | 146 ++++++++++++++++++++++++++++++++++-
>>>  include/linux/mux/consumer.h |  19 ++++-
>>>  include/linux/mux/driver.h   |  13 ++++
>>>  3 files changed, 173 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/mux/core.c b/drivers/mux/core.c
>>> index 22f4709768d1..9622b98f9818 100644
>>> --- a/drivers/mux/core.c
>>> +++ b/drivers/mux/core.c
>>> @@ -370,6 +370,29 @@ int mux_control_select_delay(struct mux_control *mux, unsigned int state,
>>>  }
>>>  EXPORT_SYMBOL_GPL(mux_control_select_delay);
>>>  
> 
> [...]
> 
>>>  }
>>>  
>>>  /**
>>> - * mux_control_get() - Get the mux-control for a device.
>>> + * mux_get() - Get the mux-control for a device.
>>>   * @dev: The device that needs a mux-control.
>>>   * @mux_name: The name identifying the mux-control.
>>> + * @enable_state: The variable to store the enable state for the requested device
>>>   *
>>>   * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
>>>   */
>>> -struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>>> +static struct mux_control *mux_get(struct device *dev, const char *mux_name,
>>> +				   unsigned int *enable_state)
>>
>> s/enable_state/state/ (goes for all of the patch).
>>
>>>  {
>>>  	struct device_node *np = dev->of_node;
>>>  	struct of_phandle_args args;
>>> @@ -481,8 +545,7 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>>>  	if (!mux_chip)
>>>  		return ERR_PTR(-EPROBE_DEFER);
>>>  
>>> -	if (args.args_count > 1 ||
>>
>> It is inconsistent to allow more than 2 args, but then only allow
>> digging out the state from the 2nd arg if the count is exactly 2.
>>
>>> -	    (!args.args_count && (mux_chip->controllers > 1))) {
>>> +	if (!args.args_count && mux_chip->controllers > 1) {
>>>  		dev_err(dev, "%pOF: wrong #mux-control-cells for %pOF\n",
>>>  			np, args.np);
>>>  		put_device(&mux_chip->dev);
>>> @@ -500,8 +563,25 @@ struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>>>  		return ERR_PTR(-EINVAL);
>>>  	}
>>>  
>>> +	if (args.args_count == 2)
>>> +		*enable_state = args.args[1];
>>> +
>>
>> With the suggested binding in my comment for patch 1/4, you'd need to do
>> either
>>
>> 	ret = of_parse_phandle_with_args(np,
>> 					 "mux-controls", "#mux-control-cells",
>> 					 index, &args);
>>
>> or
>>
>> 	ret = of_parse_phandle_with_args(np,
>> 					 "mux-states", "#mux-state-cells",
>> 					 index, &args);
>>
>> depending on if the mux_get helper gets a NULL (enable_)state pointer or a "real"
>> address, and then...
>>
> 
> 
> Sorry, while trying to implement the above method, I came across one
> more question. So, in a given consumer DT node we will be either having
> only mux-states or mux-controls right? How would we take care of the
> condition when we would want to set the state of a given line in the
> controller. Especially when a single mux chip is used by multiple
> consumers each using a different line. Wouldn't we require both
> mux-controls and mux-states in that case? So, shouldn't the
> implementation be such that we need to first read mux-controls and then
> based whether the enable_state is NULL, we read mux-states?
> 
> Just to add more clarity, if we go about this method then we would have
> both mux-controls and mux-states in the consumer DT node when we want to
> specify the state.
> 

I now understood the implementation that you described. mux-states will
be similar to the mux-controls after this patch is applied. mux-states
can have 2 arguments(mux line and state) whereas mux-controls can have
only one argument(mux line).

Sorry, for the inconvenience.

Thanks,
Aswath

> Thanks,
> Aswath
> 
>>>  	return &mux_chip->mux[controller];
>>>  }
>>> +
>>> +/**
>>> + * mux_control_get() - Get the mux-control for a device.
>>> + * @dev: The device that needs a mux-control.
>>> + * @mux_name: The name identifying the mux-control.
>>> + *
>>> + * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
>>> + */
>>> +struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
>>> +{
> 
> [...]
>
Peter Rosin Nov. 30, 2021, 8:11 a.m. UTC | #6
On 2021-11-30 06:58, Aswath Govindraju wrote:
> On 30/11/21 11:14 am, Aswath Govindraju wrote:
>> On 25/11/21 7:22 pm, Peter Rosin wrote:
>>> With the suggested binding in my comment for patch 1/4, you'd need to do
>>> either
>>>
>>> 	ret = of_parse_phandle_with_args(np,
>>> 					 "mux-controls", "#mux-control-cells",
>>> 					 index, &args);
>>>
>>> or
>>>
>>> 	ret = of_parse_phandle_with_args(np,
>>> 					 "mux-states", "#mux-state-cells",
>>> 					 index, &args);
>>>
>>> depending on if the mux_get helper gets a NULL (enable_)state pointer or a "real"
>>> address, and then...
>>>
>>
>>
>> Sorry, while trying to implement the above method, I came across one
>> more question. So, in a given consumer DT node we will be either having
>> only mux-states or mux-controls right? How would we take care of the
>> condition when we would want to set the state of a given line in the
>> controller. Especially when a single mux chip is used by multiple
>> consumers each using a different line. Wouldn't we require both
>> mux-controls and mux-states in that case? So, shouldn't the
>> implementation be such that we need to first read mux-controls and then
>> based whether the enable_state is NULL, we read mux-states?
>>
>> Just to add more clarity, if we go about this method then we would have
>> both mux-controls and mux-states in the consumer DT node when we want to
>> specify the state.
>>
> 
> I now understood the implementation that you described. mux-states will
> be similar to the mux-controls after this patch is applied. mux-states
> can have 2 arguments(mux line and state) whereas mux-controls can have
> only one argument(mux line).
> 
> Sorry, for the inconvenience.

No trouble at all. And thanks for tackling this! I think it can open up
the mux subsystem to more uses.

I'm not sure if the devicetree folks like the concept though, there has
been no comment from that direction yet. Because it does feel a bit
unusual to potentially have both #mux-control-cells and #mux-state-cells
in a single mux provider node, especially when they are as related as
they are. But sharing a mux control between several consumer is perhaps
not the most common usage, so it will probably be the exception to
require both in actual usage. But I think all that will be clearer
when/if we see the actual binding patches.

Cheers,
Peter
diff mbox series

Patch

diff --git a/drivers/mux/core.c b/drivers/mux/core.c
index 22f4709768d1..9622b98f9818 100644
--- a/drivers/mux/core.c
+++ b/drivers/mux/core.c
@@ -370,6 +370,29 @@  int mux_control_select_delay(struct mux_control *mux, unsigned int state,
 }
 EXPORT_SYMBOL_GPL(mux_control_select_delay);
 
+/**
+ * mux_state_select_delay() - Select the enable state in mux-state
+ * @mux: The mux-state to request a change of state from.
+ * @delay_us: The time to delay (in microseconds) if the mux state is changed.
+ *
+ * On successfully selecting the enable state, it will be locked until
+ * there is a call to mux_state_deselect(). If the mux-control is already
+ * selected when mux_state_select() is called, the caller will be blocked
+ * until mux_state_deselect() is called (by someone else).
+ *
+ * Therefore, make sure to call mux_state_deselect() when the operation is
+ * complete and the mux-control is free for others to use, but do not call
+ * mux_state_deselect() if mux_state_select() fails.
+ *
+ * Return: 0 when the mux-state has the enable state or a negative
+ * errno on error.
+ */
+int mux_state_select_delay(struct mux_state *mux, unsigned int delay_us)
+{
+	return mux_control_select_delay(mux->mux, mux->enable_state, delay_us);
+}
+EXPORT_SYMBOL_GPL(mux_state_select_delay);
+
 /**
  * mux_control_try_select_delay() - Try to select the given multiplexer state.
  * @mux: The mux-control to request a change of state from.
@@ -405,6 +428,27 @@  int mux_control_try_select_delay(struct mux_control *mux, unsigned int state,
 }
 EXPORT_SYMBOL_GPL(mux_control_try_select_delay);
 
+/**
+ * mux_state_try_select_delay() - Try to select the multiplexer enable state.
+ * @mux: The mux-control to request a change of state from.
+ * @delay_us: The time to delay (in microseconds) if the mux state is changed.
+ *
+ * On successfully selecting the enable state, it will be locked until
+ * mux_state_deselect() called.
+ *
+ * Therefore, make sure to call mux_state_deselect() when the operation is
+ * complete and the mux-control is free for others to use, but do not call
+ * mux_state_deselect() if mux_state_try_select() fails.
+ *
+ * Return: 0 when the mux-control state has the requested state or a negative
+ * errno on error. Specifically -EBUSY if the mux-control is contended.
+ */
+int mux_state_try_select_delay(struct mux_state *mux, unsigned int delay_us)
+{
+	return mux_control_try_select_delay(mux->mux, mux->enable_state, delay_us);
+}
+EXPORT_SYMBOL_GPL(mux_state_try_select_delay);
+
 /**
  * mux_control_deselect() - Deselect the previously selected multiplexer state.
  * @mux: The mux-control to deselect.
@@ -431,6 +475,24 @@  int mux_control_deselect(struct mux_control *mux)
 }
 EXPORT_SYMBOL_GPL(mux_control_deselect);
 
+/**
+ * mux_state_deselect() - Deselect the previously selected multiplexer state.
+ * @mux: The mux-state to deselect.
+ *
+ * It is required that a single call is made to mux_state_deselect() for
+ * each and every successful call made to either of mux_state_select() or
+ * mux_state_try_select().
+ *
+ * Return: 0 on success and a negative errno on error. An error can only
+ * occur if the mux has an idle state. Note that even if an error occurs, the
+ * mux-control is unlocked and is thus free for the next access.
+ */
+int mux_state_deselect(struct mux_state *mux)
+{
+	return mux_control_deselect(mux->mux);
+}
+EXPORT_SYMBOL_GPL(mux_state_deselect);
+
 /* Note this function returns a reference to the mux_chip dev. */
 static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
 {
@@ -442,13 +504,15 @@  static struct mux_chip *of_find_mux_chip_by_node(struct device_node *np)
 }
 
 /**
- * mux_control_get() - Get the mux-control for a device.
+ * mux_get() - Get the mux-control for a device.
  * @dev: The device that needs a mux-control.
  * @mux_name: The name identifying the mux-control.
+ * @enable_state: The variable to store the enable state for the requested device
  *
  * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
  */
-struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
+static struct mux_control *mux_get(struct device *dev, const char *mux_name,
+				   unsigned int *enable_state)
 {
 	struct device_node *np = dev->of_node;
 	struct of_phandle_args args;
@@ -481,8 +545,7 @@  struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 	if (!mux_chip)
 		return ERR_PTR(-EPROBE_DEFER);
 
-	if (args.args_count > 1 ||
-	    (!args.args_count && (mux_chip->controllers > 1))) {
+	if (!args.args_count && mux_chip->controllers > 1) {
 		dev_err(dev, "%pOF: wrong #mux-control-cells for %pOF\n",
 			np, args.np);
 		put_device(&mux_chip->dev);
@@ -500,8 +563,25 @@  struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
 		return ERR_PTR(-EINVAL);
 	}
 
+	if (args.args_count == 2)
+		*enable_state = args.args[1];
+
 	return &mux_chip->mux[controller];
 }
+
+/**
+ * mux_control_get() - Get the mux-control for a device.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: A pointer to the mux-control, or an ERR_PTR with a negative errno.
+ */
+struct mux_control *mux_control_get(struct device *dev, const char *mux_name)
+{
+	int state;
+
+	return mux_get(dev, mux_name, &state);
+}
 EXPORT_SYMBOL_GPL(mux_control_get);
 
 /**
@@ -523,6 +603,26 @@  static void devm_mux_control_release(struct device *dev, void *res)
 	mux_control_put(mux);
 }
 
+/**
+ * mux_state_put() - Put away the mux-state for good.
+ * @mux: The mux-state to put away.
+ *
+ * mux_control_put() reverses the effects of mux_control_get().
+ */
+void mux_state_put(struct mux_state *mux_state)
+{
+	mux_control_put(mux_state->mux);
+	kfree(mux_state);
+}
+EXPORT_SYMBOL_GPL(mux_state_put);
+
+static void devm_mux_state_release(struct device *dev, void *res)
+{
+	struct mux_state *mux = *(struct mux_state **)res;
+
+	mux_state_put(mux);
+}
+
 /**
  * devm_mux_control_get() - Get the mux-control for a device, with resource
  *			    management.
@@ -553,6 +653,44 @@  struct mux_control *devm_mux_control_get(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(devm_mux_control_get);
 
+/**
+ * devm_mux_state_get() - Get the mux-state for a device, with resource
+ *			  management.
+ * @dev: The device that needs a mux-control.
+ * @mux_name: The name identifying the mux-control.
+ *
+ * Return: Pointer to the mux-state, or an ERR_PTR with a negative errno.
+ */
+struct mux_state *devm_mux_state_get(struct device *dev,
+				     const char *mux_name)
+{
+	struct mux_state **ptr, *mux_state;
+	struct mux_control *mux_ctrl;
+	int enable_state;
+
+	mux_state = devm_kzalloc(dev, sizeof(struct mux_state), GFP_KERNEL);
+	if (!mux_state)
+		return ERR_PTR(-ENOMEM);
+
+	ptr = devres_alloc(devm_mux_state_release, sizeof(*ptr), GFP_KERNEL);
+	if (!ptr)
+		return ERR_PTR(-ENOMEM);
+
+	mux_ctrl = mux_get(dev, mux_name, &enable_state);
+	if (IS_ERR(mux_ctrl)) {
+		devres_free(ptr);
+		return (struct mux_state *)mux_ctrl;
+	}
+
+	mux_state->mux = mux_ctrl;
+	mux_state->enable_state = enable_state;
+	*ptr = mux_state;
+	devres_add(dev, ptr);
+
+	return mux_state;
+}
+EXPORT_SYMBOL_GPL(devm_mux_state_get);
+
 /*
  * Using subsys_initcall instead of module_init here to try to ensure - for
  * the non-modular case - that the subsystem is initialized when mux consumers
diff --git a/include/linux/mux/consumer.h b/include/linux/mux/consumer.h
index 7a09b040ac39..d0f3242e148d 100644
--- a/include/linux/mux/consumer.h
+++ b/include/linux/mux/consumer.h
@@ -14,33 +14,50 @@ 
 
 struct device;
 struct mux_control;
+struct mux_state;
 
 unsigned int mux_control_states(struct mux_control *mux);
 int __must_check mux_control_select_delay(struct mux_control *mux,
 					  unsigned int state,
 					  unsigned int delay_us);
+int __must_check mux_state_select_delay(struct mux_state *mux,
+					unsigned int delay_us);
 int __must_check mux_control_try_select_delay(struct mux_control *mux,
 					      unsigned int state,
 					      unsigned int delay_us);
-
+int __must_check mux_state_try_select_delay(struct mux_state *mux,
+					    unsigned int delay_us);
 static inline int __must_check mux_control_select(struct mux_control *mux,
 						  unsigned int state)
 {
 	return mux_control_select_delay(mux, state, 0);
 }
 
+static inline int __must_check mux_state_select(struct mux_state *mux)
+{
+	return mux_state_select_delay(mux, 0);
+}
 static inline int __must_check mux_control_try_select(struct mux_control *mux,
 						      unsigned int state)
 {
 	return mux_control_try_select_delay(mux, state, 0);
 }
 
+static inline int __must_check mux_state_try_select(struct mux_state *mux)
+{
+	return mux_state_try_select_delay(mux, 0);
+}
+
 int mux_control_deselect(struct mux_control *mux);
+int mux_state_deselect(struct mux_state *mux);
 
 struct mux_control *mux_control_get(struct device *dev, const char *mux_name);
 void mux_control_put(struct mux_control *mux);
+void mux_state_put(struct mux_state *mux);
 
 struct mux_control *devm_mux_control_get(struct device *dev,
 					 const char *mux_name);
+struct mux_state *devm_mux_state_get(struct device *dev,
+				     const char *mux_name);
 
 #endif /* _LINUX_MUX_CONSUMER_H */
diff --git a/include/linux/mux/driver.h b/include/linux/mux/driver.h
index 18824064f8c0..c7236f307fbd 100644
--- a/include/linux/mux/driver.h
+++ b/include/linux/mux/driver.h
@@ -53,6 +53,19 @@  struct mux_control {
 	ktime_t last_change;
 };
 
+/**
+ * struct mux_state -	Represents a mux controller specific to a given device
+ * @mux:		Pointer to a mux controller
+ * @enable_state	State of the mux to be set for enabling a device
+ *
+ * This structure is specific to a device that acquires it and has information
+ * specific to the device.
+ */
+struct mux_state {
+	struct mux_control *mux;
+	unsigned int enable_state;
+};
+
 /**
  * struct mux_chip -	Represents a chip holding mux controllers.
  * @controllers:	Number of mux controllers handled by the chip.