Mark,
There's one small issue with the WM8903 DMIC patch I sent recently:
In HW, there's a single control bit that affects two paths. This is currently represented as two widgets, Left ADC Input and Right ADC Input, each having its own control, both of which point at the same register bit.
When alsamixer sets one of these controls, both the Left ADC Input and Right ADC Input controls read back with the value that was set, since they both read from the same register bit. However, if only one of the controls is actually manipulated, then only the paths associated with that single widget are updated by dapm_mux_update_power. To solve this, the user must currently also toggle the other control back to the original value and then to the new value in order to update the paths.
I can see some possible ways to solve this, presented below:
Solution 1: Applying updates to N controls:
Modify snd_soc_dapm_put_* to search for and loop over all widgets using the same control name or register bit(s) in, and perform the same update for each.
Essentially, this is the same idea as solution 2 below, but with the implementation performing all the comparisons within snd_soc_dapm_put_*, rather than pre-computing the sharing arrangement when creating controls.
The disadvantage here is the perhaps significant run-time comparison costs within the loop over all widgets. Also, each snd_soc_dapm_put_* duplicates that same code, unless the control's .get/.put point at a single unified ASoC function which implements the looping, and then dispatches based on a different function pointer.
Solution 2: Sharing controls:
* When calling snd_soc_cnew, store a list of widgets in the control instead of a single widget.
* Modify snd_soc_dapm_{get,put}_* to retrieve the list of widgets, and iterate over them all.
* Modify dapm_new_{mux,*} to:
+ Search for an existing control with the same name.
+ If found: Add this widget to the list stored in the control.
+ If not found: Create a new control with a single-entry list containing the current widget.
The advantage here is isolating the searching for widgets using the same register bits to control creation rather than usage.
Data setup would be:
// Two mono muxes, sharing a control SND_SOC_DAPM_MUX("Left ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux), SND_SOC_DAPM_MUX("Right ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
// Existing style of path definitions { "Left ADC Input", "ADC", "Left Input PGA" }, { "Left ADC Input", "DMIC", "DMICDAT" }, { "Right ADC Input", "ADC", "Right Input PGA" }, { "Right ADC Input", "DMIC", "DMICDAT" }, { "ADCL", NULL, "Left ADC Input" }, { "ADCL", NULL, "CLK_DSP" }, { "ADCR", NULL, "Right ADC Input" }, { "ADCR", NULL, "CLK_DSP" },
Solution 3: Stereo widgets:
* Modify w->{sources,sinks} to be arrays (an entry for each channel, probably just L/R entries initially)
* Modify path list parsing to allow source/sink widget names to contain a ":L"/":R" suffix indicating which w->sources[] array index to use.
The arrays would be required so that path traversal code wouldn't find a false path from ADCR to Right Input PGA; the L/R connectivity needs to be completely separate.
* snd_soc_dapm_add_route's "find src and dest widgets" loop would need to be enhanced to understand the new syntax, and be able to match up widget names by ignoring ":xxx" when searching, at least for widgets explicitly marked stereo.
* Other fallout of the above that I haven't thought through yet.
// A single stereo mux SND_SOC_DAPM_MUX("ADC Input", SND_SOC_NOPM, 0, 0, &adcinput_mux),
// Enhanced style of path definitions { "ADC Input:L", "ADC", "Left Input PGA" }, { "ADC Input:L", "DMIC", "DMICDAT" }, { "ADC Input:R", "ADC", "Right Input PGA" }, { "ADC Input:R", "DMIC", "DMICDAT" }, { "ADCL", NULL, "ADC Input:R" }, { "ADCL", NULL, "CLK_DSP" }, { "ADCR", NULL, "ADC Input:R" }, { "ADCR", NULL, "CLK_DSP" },
Do you have any other ideas how this might be solved, or a preference for which solution to pursue?
Thanks.