diff options
author | Mark Brown <broonie@kernel.org> | 2021-12-23 19:38:13 +0000 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2021-12-23 19:38:13 +0000 |
commit | 2f15d3cebd45f773a2e27cce84ca851164dd5acd (patch) | |
tree | e3af59b4e59c97ffd315ee4b2c73fcd744f340ac | |
parent | 4e28491a7a198c668437f2be8a91a76aa52f20eb (diff) | |
parent | 319a05330f4ff3f951f9c42094958c6cdef393b3 (diff) |
ASoC: qcom: Parse "pin-switches" and "widgets" from DT
Merge series from Stephan Gerhold <stephan@gerhold.net>:
Some sound card setups might require extra pin switches to allow
turning off certain audio components. simple-card supports this
already using the "pin-switches" and "widgets" device tree property.
This series makes it possible to use the same properties for the Qcom
sound cards.
To implement that, the function that parses the "pin-switches" property
in simple-card-utils.c is first moved into the ASoC core. Then two
simple function calls are added to the common Qcom sound card DT parser.
Finally there is a small patch for the msm8916-wcd-analog codec to make
it possible to model sound card setups used in some MSM8916 smartphones.
(See PATCH 2/4 for an explanation of some real example use cases.)
Using pin switches rather than patching codec drivers with switches was
originally suggested by Mark Brown on a patch for the tfa989x codec:
https://lore.kernel.org/alsa-devel/YXaMVHo9drCIuD3u@sirena.org.uk/
-rw-r--r-- | Documentation/devicetree/bindings/sound/qcom,sm8250.yaml | 16 | ||||
-rw-r--r-- | include/sound/soc.h | 1 | ||||
-rw-r--r-- | sound/soc/codecs/msm8916-wcd-analog.c | 7 | ||||
-rw-r--r-- | sound/soc/generic/simple-card-utils.c | 45 | ||||
-rw-r--r-- | sound/soc/qcom/common.c | 10 | ||||
-rw-r--r-- | sound/soc/soc-core.c | 50 |
6 files changed, 82 insertions, 47 deletions
diff --git a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml index e50964c54bb9..4bfda04b4608 100644 --- a/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml +++ b/Documentation/devicetree/bindings/sound/qcom,sm8250.yaml @@ -39,6 +39,14 @@ properties: $ref: /schemas/types.yaml#/definitions/string description: User visible long sound card name + pin-switches: + description: List of widget names for which pin switches should be created. + $ref: /schemas/types.yaml#/definitions/string-array + + widgets: + description: User specified audio sound widgets. + $ref: /schemas/types.yaml#/definitions/non-unique-string-array + # Only valid for some compatibles (see allOf if below) reg: true reg-names: true @@ -251,7 +259,15 @@ examples: reg-names = "mic-iomux", "spkr-iomux"; model = "msm8916"; + widgets = + "Speaker", "Speaker", + "Headphone", "Headphones"; + pin-switches = "Speaker"; audio-routing = + "Speaker", "Speaker Amp OUT", + "Speaker Amp IN", "HPH_R", + "Headphones", "HPH_L", + "Headphones", "HPH_R", "AMIC1", "MIC BIAS Internal1", "AMIC2", "MIC BIAS Internal2", "AMIC3", "MIC BIAS Internal3"; diff --git a/include/sound/soc.h b/include/sound/soc.h index 5872a8864f3b..7a1650b303f1 100644 --- a/include/sound/soc.h +++ b/include/sound/soc.h @@ -1211,6 +1211,7 @@ int snd_soc_of_parse_card_name(struct snd_soc_card *card, const char *propname); int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, const char *propname); +int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop); int snd_soc_of_get_slot_mask(struct device_node *np, const char *prop_name, unsigned int *mask); diff --git a/sound/soc/codecs/msm8916-wcd-analog.c b/sound/soc/codecs/msm8916-wcd-analog.c index 3ddd822240e3..485cda46dbb9 100644 --- a/sound/soc/codecs/msm8916-wcd-analog.c +++ b/sound/soc/codecs/msm8916-wcd-analog.c @@ -822,8 +822,8 @@ static const struct snd_soc_dapm_route pm8916_wcd_analog_audio_map[] = { {"EAR PA", NULL, "EAR CP"}, /* Headset (RX MIX1 and RX MIX2) */ - {"HEADPHONE", NULL, "HPHL PA"}, - {"HEADPHONE", NULL, "HPHR PA"}, + {"HPH_L", NULL, "HPHL PA"}, + {"HPH_R", NULL, "HPHR PA"}, {"HPHL DAC", NULL, "EAR_HPHL_CLK"}, {"HPHR DAC", NULL, "EAR_HPHR_CLK"}, @@ -870,7 +870,8 @@ static const struct snd_soc_dapm_widget pm8916_wcd_analog_dapm_widgets[] = { SND_SOC_DAPM_INPUT("AMIC3"), SND_SOC_DAPM_INPUT("AMIC2"), SND_SOC_DAPM_OUTPUT("EAR"), - SND_SOC_DAPM_OUTPUT("HEADPHONE"), + SND_SOC_DAPM_OUTPUT("HPH_L"), + SND_SOC_DAPM_OUTPUT("HPH_R"), /* RX stuff */ SND_SOC_DAPM_SUPPLY("INT_LDO_H", SND_SOC_NOPM, 1, 0, NULL, 0), diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c index 850e968677f1..a81323d1691d 100644 --- a/sound/soc/generic/simple-card-utils.c +++ b/sound/soc/generic/simple-card-utils.c @@ -499,57 +499,14 @@ EXPORT_SYMBOL_GPL(asoc_simple_parse_widgets); int asoc_simple_parse_pin_switches(struct snd_soc_card *card, char *prefix) { - const unsigned int nb_controls_max = 16; - const char **strings, *control_name; - struct snd_kcontrol_new *controls; - struct device *dev = card->dev; - unsigned int i, nb_controls; char prop[128]; - int ret; if (!prefix) prefix = ""; snprintf(prop, sizeof(prop), "%s%s", prefix, "pin-switches"); - if (!of_property_read_bool(dev->of_node, prop)) - return 0; - - strings = devm_kcalloc(dev, nb_controls_max, - sizeof(*strings), GFP_KERNEL); - if (!strings) - return -ENOMEM; - - ret = of_property_read_string_array(dev->of_node, prop, - strings, nb_controls_max); - if (ret < 0) - return ret; - - nb_controls = (unsigned int)ret; - - controls = devm_kcalloc(dev, nb_controls, - sizeof(*controls), GFP_KERNEL); - if (!controls) - return -ENOMEM; - - for (i = 0; i < nb_controls; i++) { - control_name = devm_kasprintf(dev, GFP_KERNEL, - "%s Switch", strings[i]); - if (!control_name) - return -ENOMEM; - - controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; - controls[i].name = control_name; - controls[i].info = snd_soc_dapm_info_pin_switch; - controls[i].get = snd_soc_dapm_get_pin_switch; - controls[i].put = snd_soc_dapm_put_pin_switch; - controls[i].private_value = (unsigned long)strings[i]; - } - - card->controls = controls; - card->num_controls = nb_controls; - - return 0; + return snd_soc_of_parse_pin_switches(card, prop); } EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches); diff --git a/sound/soc/qcom/common.c b/sound/soc/qcom/common.c index e1bf04d00625..c407684ce1a2 100644 --- a/sound/soc/qcom/common.c +++ b/sound/soc/qcom/common.c @@ -26,6 +26,12 @@ int qcom_snd_parse_of(struct snd_soc_card *card) return ret; } + if (of_property_read_bool(dev->of_node, "widgets")) { + ret = snd_soc_of_parse_audio_simple_widgets(card, "widgets"); + if (ret) + return ret; + } + /* DAPM routes */ if (of_property_read_bool(dev->of_node, "audio-routing")) { ret = snd_soc_of_parse_audio_routing(card, "audio-routing"); @@ -39,6 +45,10 @@ int qcom_snd_parse_of(struct snd_soc_card *card) return ret; } + ret = snd_soc_of_parse_pin_switches(card, "pin-switches"); + if (ret) + return ret; + ret = snd_soc_of_parse_aux_devs(card, "aux-devs"); if (ret) return ret; diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c index 1d62160f96b1..434e61b46983 100644 --- a/sound/soc/soc-core.c +++ b/sound/soc/soc-core.c @@ -2823,6 +2823,56 @@ int snd_soc_of_parse_audio_simple_widgets(struct snd_soc_card *card, } EXPORT_SYMBOL_GPL(snd_soc_of_parse_audio_simple_widgets); +int snd_soc_of_parse_pin_switches(struct snd_soc_card *card, const char *prop) +{ + const unsigned int nb_controls_max = 16; + const char **strings, *control_name; + struct snd_kcontrol_new *controls; + struct device *dev = card->dev; + unsigned int i, nb_controls; + int ret; + + if (!of_property_read_bool(dev->of_node, prop)) + return 0; + + strings = devm_kcalloc(dev, nb_controls_max, + sizeof(*strings), GFP_KERNEL); + if (!strings) + return -ENOMEM; + + ret = of_property_read_string_array(dev->of_node, prop, + strings, nb_controls_max); + if (ret < 0) + return ret; + + nb_controls = (unsigned int)ret; + + controls = devm_kcalloc(dev, nb_controls, + sizeof(*controls), GFP_KERNEL); + if (!controls) + return -ENOMEM; + + for (i = 0; i < nb_controls; i++) { + control_name = devm_kasprintf(dev, GFP_KERNEL, + "%s Switch", strings[i]); + if (!control_name) + return -ENOMEM; + + controls[i].iface = SNDRV_CTL_ELEM_IFACE_MIXER; + controls[i].name = control_name; + controls[i].info = snd_soc_dapm_info_pin_switch; + controls[i].get = snd_soc_dapm_get_pin_switch; + controls[i].put = snd_soc_dapm_put_pin_switch; + controls[i].private_value = (unsigned long)strings[i]; + } + + card->controls = controls; + card->num_controls = nb_controls; + + return 0; +} +EXPORT_SYMBOL_GPL(snd_soc_of_parse_pin_switches); + int snd_soc_of_get_slot_mask(struct device_node *np, const char *prop_name, unsigned int *mask) |