ASoC: Add support for multi register mux
diff mbox

Message ID 1395186692-11735-1-git-send-email-aruns@nvidia.com
State New, archived
Headers show

Commit Message

Arun Shamanna Lakshmi March 18, 2014, 11:51 p.m. UTC
Currently soc_enum structure supports only 2 registers (reg, reg2)
for kcontrol. However, it is possible to have multiple registers
per mux. This change allows us to control these multiple registers.

Signed-off-by: Arun Shamanna Lakshmi <aruns@nvidia.com>
Signed-off-by: Songhee Baek <sbaek@nvidia.com>
---
 include/sound/soc.h |    3 +++
 1 file changed, 3 insertions(+)

Comments

Mark Brown March 18, 2014, 11:59 p.m. UTC | #1
On Tue, Mar 18, 2014 at 04:51:32PM -0700, Arun Shamanna Lakshmi wrote:

> Currently soc_enum structure supports only 2 registers (reg, reg2)
> for kcontrol. However, it is possible to have multiple registers
> per mux. This change allows us to control these multiple registers.

I'd want to see a user along with this and...

> @@ -1093,6 +1093,9 @@ struct soc_enum {
>  	unsigned int mask;
>  	const char * const *texts;
>  	const unsigned int *values;
> +	unsigned int *regs;
> +	unsigned int *masks;
> +	unsigned int num_regs;

...it duplicates and generally isn't joined up with the existing members
of the structure, and has no support in the helpers (for example,
converting the existing stereo controls to be two element arrays which
I'd expect to see).  Helpers would count as users here.

Note that we don't support double register enums or muxes - only
numerical controls are supported.  It's not clear what a multi-register
enum would mean.
Arun Shamanna Lakshmi March 19, 2014, 11:44 p.m. UTC | #2
If each bit of a 32 bit register maps to an input of a mux, then with the current 'soc_enum' structure we cannot have more than 64 inputs for the mux (because of reg and reg2 only).
In such cases, we need more than 2 registers to select the input of the mux. This is referred to as 'multi register mux' 

For instance, the audio xbar (AXBAR) module acts as a mux selecting various inputs (reference: Tegra K1 manual).

The number of such inputs increases with future Tegra chips and so will be the need to control multiple registers per mux in DAPM.  We have 2 options to achieve that.

Option 1: Using custom get and put functions something similar to below inside AXBAR tegra driver.

	int tegra_xbar_get_value_enum(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
	{
		struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
		struct snd_soc_dapm_widget *widget = wlist->widgets[0];
		struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
		unsigned int reg_val, mux, find, reg_idx;
		unsigned int num_regs = 3, regs[3];

		/* control 3 registers that has a common STRIDE */
		regs[0] = e-> reg;
		regs[1] = regs[0] + MUX_REG_STRIDE;
		regs[2] = regs[1] + MUX_REG_STRIDE;

		for (mux = 0; mux < e->max; mux++) {
			find = 0;
			for (reg_idx = 0; reg_idx < num_regs; reg_idx++) {
				regmap_read(widget->codec->control_data,
						regs[reg_idx], &reg_val);
				if (reg_val ==  e->values[mux * num_regs + reg_idx])
					find++;
			}
			if (find == num_regs)
				break;
		}
		ucontrol->value.enumerated.item[0] = mux;
		return 0;
	}

	int tegra_xbar_put_value_enum(struct snd_kcontrol *kcontrol,
				struct snd_ctl_elem_value *ucontrol)
	{
		struct snd_soc_dapm_widget_list *wlist = snd_kcontrol_chip(kcontrol);
		struct snd_soc_dapm_widget *widget = wlist->widgets[0];
		struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
		unsigned int value, mux, old, reg_idx;
		struct snd_soc_dapm_update update;
		   unsigned int num_regs = 3, regs[3], masks[3] = { 0xf1f03ff, 0x3f30031f, 0xff1cf313};
		int wi;

		regs[0] = e-> reg;
		regs[1] = regs[0] + MUX_REG_STRIDE;
		regs[2] = regs[1] + MUX_REG_STRIDE;

		if (ucontrol->value.enumerated.item[0] > e->max - 1)
			return -EINVAL;

		mux = ucontrol->value.enumerated.item[0];

		for (reg_idx = 0; reg_idx < num_regs; reg_idx++) {
			value = e->values[ucontrol->value.enumerated.item[0] * num_regs + reg_idx];
			regmap_read(widget->codec->control_data, regs[reg_idx], &old);

			if (value != old) {
				for (wi = 0; wi < wlist->num_widgets; wi++) {
					widget = wlist->widgets[wi];
					widget->value = value;
					update.kcontrol = kcontrol;
					update.widget = widget;
					update.reg = regs[reg_idx];
					update.mask = masks[reg_idx];
					update.val = value;
					widget->dapm->update = &update;
					snd_soc_dapm_mux_update_power(widget, kcontrol, mux, e);
					widget->dapm->update = NULL;
				}
			}
		}
		return 0;
	}

Option 2: Modify soc_enum structure and make 'reg' variable as reg[MAX_REG]

This would also mean that we should edit all the macros in soc.h, soc-dapm.c and soc-core.c to use 'reg[0]' instead of 'reg'
Our goal is to eventually add support to do multi register mux in get and put handlers inside soc-dapm.c upstream.

With Option1, we don't need to change any code in upstream as each register among the multiple registers has a common STRIDE (address offset). Thus, option1 is not generic enough.
If you suggest Option1, we wanted to check if upstream will be okay with such a structure. (it will be tegra specific though).

With Option2, it  becomes easy to add new macros for multi register mux in soc.h and then, add new get and put handlers in dapm.c

Thanks,
Arun

-----Original Message-----
From: Mark Brown [mailto:broonie@kernel.org] 
Sent: Tuesday, March 18, 2014 5:00 PM
To: Arun Shamanna Lakshmi
Cc: lgirdwood@gmail.com; perex@perex.cz; tiwai@suse.de; alsa-devel@alsa-project.org; linux-kernel@vger.kernel.org; Songhee Baek
Subject: Re: [PATCH] ASoC: Add support for multi register mux

* PGP Signed by an unknown key

On Tue, Mar 18, 2014 at 04:51:32PM -0700, Arun Shamanna Lakshmi wrote:

> Currently soc_enum structure supports only 2 registers (reg, reg2) for 
> kcontrol. However, it is possible to have multiple registers per mux. 
> This change allows us to control these multiple registers.

I'd want to see a user along with this and...

> @@ -1093,6 +1093,9 @@ struct soc_enum {
>  	unsigned int mask;
>  	const char * const *texts;
>  	const unsigned int *values;
> +	unsigned int *regs;
> +	unsigned int *masks;
> +	unsigned int num_regs;

...it duplicates and generally isn't joined up with the existing members of the structure, and has no support in the helpers (for example, converting the existing stereo controls to be two element arrays which I'd expect to see).  Helpers would count as users here.

Note that we don't support double register enums or muxes - only numerical controls are supported.  It's not clear what a multi-register enum would mean.

* Unknown Key
* 0x7EA229BD
Mark Brown March 20, 2014, 11:48 a.m. UTC | #3
On Wed, Mar 19, 2014 at 04:44:00PM -0700, Arun Shamanna Lakshmi wrote:

Don't top post and fix your mailer to word wrap within paragraphs, your
mail is very hard to read.

> If each bit of a 32 bit register maps to an input of a mux, then with
> the current 'soc_enum' structure we cannot have more than 64 inputs
> for the mux (because of reg and reg2 only).

What makes you say that?  We currently have devices in mainline which
have well over 32 inputs to muxes.

> For instance, the audio xbar (AXBAR) module acts as a mux selecting
> various inputs (reference: Tegra K1 manual).

I don't have access to non-public nVidia documents...

> The number of such inputs increases with future Tegra chips and so
> will be the need to control multiple registers per mux in DAPM.  We
> have 2 options to achieve that.

Like I said in my previous reply I would expect to see some users along
with the code, extending the standard helpers to support this would be a
much better idea than doing something driver custom.
Stephen Warren March 20, 2014, 6:20 p.m. UTC | #4
On 03/20/2014 05:48 AM, Mark Brown wrote:
> On Wed, Mar 19, 2014 at 04:44:00PM -0700, Arun Shamanna Lakshmi wrote:
> 
> Don't top post and fix your mailer to word wrap within paragraphs, your
> mail is very hard to read.
> 
>> If each bit of a 32 bit register maps to an input of a mux, then with
>> the current 'soc_enum' structure we cannot have more than 64 inputs
>> for the mux (because of reg and reg2 only).
> 
> What makes you say that?  We currently have devices in mainline which
> have well over 32 inputs to muxes.

I think their register layout is different.

I found a number of large muxes where the register stores a 'integer'
indicating which mux input to select, e.g. Arizona, WM2200, etc. In this
case, an N-bit register could support up to 2^N inputs.

However, the registers in the Tegra AHUB use 1 bit position per input,
and require you to set one single bit at a time. Hence, an N bit
register (or string of registers) can support up to N inputs. In more
recent Tegra chips, we have at least >32 inputs and I think Arun was
saying even >64 inputs. That requires 2 or 3 or more .reg fields in
struct soc_enum.
Mark Brown March 20, 2014, 6:36 p.m. UTC | #5
On Thu, Mar 20, 2014 at 12:20:17PM -0600, Stephen Warren wrote:
> On 03/20/2014 05:48 AM, Mark Brown wrote:
> > On Wed, Mar 19, 2014 at 04:44:00PM -0700, Arun Shamanna Lakshmi wrote:

> >> If each bit of a 32 bit register maps to an input of a mux, then with
> >> the current 'soc_enum' structure we cannot have more than 64 inputs
> >> for the mux (because of reg and reg2 only).

> > What makes you say that?  We currently have devices in mainline which
> > have well over 32 inputs to muxes.

> I think their register layout is different.

> I found a number of large muxes where the register stores a 'integer'
> indicating which mux input to select, e.g. Arizona, WM2200, etc. In this
> case, an N-bit register could support up to 2^N inputs.

> However, the registers in the Tegra AHUB use 1 bit position per input,
> and require you to set one single bit at a time. Hence, an N bit
> register (or string of registers) can support up to N inputs. In more
> recent Tegra chips, we have at least >32 inputs and I think Arun was
> saying even >64 inputs. That requires 2 or 3 or more .reg fields in
> struct soc_enum.

Right, that was my guess too (the mail wasn't terribly clear with the
formatting, references to unpublished documents and so on) but that's
not a straight mux, it's a value mux, and the limit with the current
code is much lower on 32 bit systems (like at least some of the K1s)
since muxes only use one of the current register fields.
Lars-Peter Clausen March 20, 2014, 7:05 p.m. UTC | #6
On 03/20/2014 07:36 PM, Mark Brown wrote:
> On Thu, Mar 20, 2014 at 12:20:17PM -0600, Stephen Warren wrote:
>> On 03/20/2014 05:48 AM, Mark Brown wrote:
>>> On Wed, Mar 19, 2014 at 04:44:00PM -0700, Arun Shamanna Lakshmi wrote:
>
>>>> If each bit of a 32 bit register maps to an input of a mux, then with
>>>> the current 'soc_enum' structure we cannot have more than 64 inputs
>>>> for the mux (because of reg and reg2 only).
>
>>> What makes you say that?  We currently have devices in mainline which
>>> have well over 32 inputs to muxes.
>
>> I think their register layout is different.
>
>> I found a number of large muxes where the register stores a 'integer'
>> indicating which mux input to select, e.g. Arizona, WM2200, etc. In this
>> case, an N-bit register could support up to 2^N inputs.
>
>> However, the registers in the Tegra AHUB use 1 bit position per input,
>> and require you to set one single bit at a time. Hence, an N bit
>> register (or string of registers) can support up to N inputs. In more
>> recent Tegra chips, we have at least >32 inputs and I think Arun was
>> saying even >64 inputs. That requires 2 or 3 or more .reg fields in
>> struct soc_enum.
>
> Right, that was my guess too (the mail wasn't terribly clear with the
> formatting, references to unpublished documents and so on) but that's
> not a straight mux, it's a value mux, and the limit with the current
> code is much lower on 32 bit systems (like at least some of the K1s)
> since muxes only use one of the current register fields.

It might make sense to add special code for supported muxes with a one-hot 
encoding instead of using a value mux. Having an large array where each 
entry is just 1<<n is a bit ugly in my opinion, especially if the value 
needs to be able to be larger than 2**64. But anyway the patch that modifies 
the soc_enum struct should also add the code that makes use of the new 
struct layout.

- Lars
Lars-Peter Clausen March 20, 2014, 7:40 p.m. UTC | #7
On 03/20/2014 08:05 PM, Lars-Peter Clausen wrote:
> On 03/20/2014 07:36 PM, Mark Brown wrote:
>> On Thu, Mar 20, 2014 at 12:20:17PM -0600, Stephen Warren wrote:
>>> On 03/20/2014 05:48 AM, Mark Brown wrote:
>>>> On Wed, Mar 19, 2014 at 04:44:00PM -0700, Arun Shamanna Lakshmi wrote:
>>
>>>>> If each bit of a 32 bit register maps to an input of a mux, then with
>>>>> the current 'soc_enum' structure we cannot have more than 64 inputs
>>>>> for the mux (because of reg and reg2 only).
>>
>>>> What makes you say that?  We currently have devices in mainline which
>>>> have well over 32 inputs to muxes.
>>
>>> I think their register layout is different.
>>
>>> I found a number of large muxes where the register stores a 'integer'
>>> indicating which mux input to select, e.g. Arizona, WM2200, etc. In this
>>> case, an N-bit register could support up to 2^N inputs.
>>
>>> However, the registers in the Tegra AHUB use 1 bit position per input,
>>> and require you to set one single bit at a time. Hence, an N bit
>>> register (or string of registers) can support up to N inputs. In more
>>> recent Tegra chips, we have at least >32 inputs and I think Arun was
>>> saying even >64 inputs. That requires 2 or 3 or more .reg fields in
>>> struct soc_enum.
>>
>> Right, that was my guess too (the mail wasn't terribly clear with the
>> formatting, references to unpublished documents and so on) but that's
>> not a straight mux, it's a value mux, and the limit with the current
>> code is much lower on 32 bit systems (like at least some of the K1s)
>> since muxes only use one of the current register fields.
>
> It might make sense to add special code for supported muxes with a one-hot
> encoding instead of using a value mux. Having an large array where each
> entry is just 1<<n is a bit ugly in my opinion, especially if the value
> needs to be able to be larger than 2**64. But anyway the patch that modifies
> the soc_enum struct should also add the code that makes use of the new
> struct layout.

On the other hand this can actually already be implemented without any core 
changes by using a virtual mux and connecting a supply widget to each input 
which sets the bit for that input. DAPM will take care that only one of the 
supply widgets is enabled at a time.

- Lars
Mark Brown March 21, 2014, 11:37 a.m. UTC | #8
On Thu, Mar 20, 2014 at 08:40:54PM +0100, Lars-Peter Clausen wrote:
> On 03/20/2014 08:05 PM, Lars-Peter Clausen wrote:

> >It might make sense to add special code for supported muxes with a one-hot
> >encoding instead of using a value mux. Having an large array where each
> >entry is just 1<<n is a bit ugly in my opinion, especially if the value
> >needs to be able to be larger than 2**64. But anyway the patch that modifies
> >the soc_enum struct should also add the code that makes use of the new
> >struct layout.

> On the other hand this can actually already be implemented without any core
> changes by using a virtual mux and connecting a supply widget to each input
> which sets the bit for that input. DAPM will take care that only one of the
> supply widgets is enabled at a time.

Yes, each works - either way I think we can probably come up with some
helpers in the header which hide the actual implementation from the
drivers or at least makes it obvious that this is the way to do things.
The supply widgets approach wouldn't need any changes in the core but
then generalising the two register code isn't a bad thing anyway.

Patch
diff mbox

diff --git a/include/sound/soc.h b/include/sound/soc.h
index 9a00147..ddedfb4 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -1093,6 +1093,9 @@  struct soc_enum {
 	unsigned int mask;
 	const char * const *texts;
 	const unsigned int *values;
+	unsigned int *regs;
+	unsigned int *masks;
+	unsigned int num_regs;
 };
 
 /* codec IO */