diff options
-rw-r--r-- | sound/soc/codecs/Kconfig | 1 | ||||
-rw-r--r-- | sound/soc/codecs/wcd938x.c | 55 |
2 files changed, 45 insertions, 11 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 40bb7a1d44bc..870eb90116f1 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -2239,6 +2239,7 @@ config SND_SOC_WCD938X tristate depends on SOUNDWIRE || !SOUNDWIRE select SND_SOC_WCD_CLASSH + select MULTIPLEXER config SND_SOC_WCD938X_SDW tristate "WCD9380/WCD9385 Codec - SDW" diff --git a/sound/soc/codecs/wcd938x.c b/sound/soc/codecs/wcd938x.c index d03ed9cfa530..585a92772c2a 100644 --- a/sound/soc/codecs/wcd938x.c +++ b/sound/soc/codecs/wcd938x.c @@ -19,6 +19,7 @@ #include <linux/regmap.h> #include <sound/soc.h> #include <sound/soc-dapm.h> +#include <linux/mux/consumer.h> #include <linux/regulator/consumer.h> #include "wcd-clsh-v2.h" @@ -173,6 +174,8 @@ struct wcd938x_priv { int variant; int reset_gpio; struct gpio_desc *us_euro_gpio; + struct mux_control *us_euro_mux; + unsigned int mux_state; u32 micb1_mv; u32 micb2_mv; u32 micb3_mv; @@ -183,6 +186,7 @@ struct wcd938x_priv { bool comp1_enable; bool comp2_enable; bool ldoh; + bool mux_setup_done; }; static const SNDRV_CTL_TLVD_DECLARE_DB_MINMAX(ear_pa_gain, 600, -1800); @@ -3232,15 +3236,26 @@ static void wcd938x_dt_parse_micbias_info(struct device *dev, struct wcd938x_pri static bool wcd938x_swap_gnd_mic(struct snd_soc_component *component) { - int value; - - struct wcd938x_priv *wcd938x; + struct wcd938x_priv *wcd938x = snd_soc_component_get_drvdata(component); + struct device *dev = component->dev; + int ret; - wcd938x = snd_soc_component_get_drvdata(component); + if (wcd938x->us_euro_mux) { + if (wcd938x->mux_setup_done) + mux_control_deselect(wcd938x->us_euro_mux); - value = gpiod_get_value(wcd938x->us_euro_gpio); + ret = mux_control_try_select(wcd938x->us_euro_mux, !wcd938x->mux_state); + if (ret) { + dev_err(dev, "Error (%d) Unable to select us/euro mux state\n", ret); + wcd938x->mux_setup_done = false; + return false; + } + wcd938x->mux_setup_done = true; + } else { + gpiod_set_value(wcd938x->us_euro_gpio, !wcd938x->mux_state); + } - gpiod_set_value(wcd938x->us_euro_gpio, !value); + wcd938x->mux_state = !wcd938x->mux_state; return true; } @@ -3256,11 +3271,26 @@ static int wcd938x_populate_dt_data(struct wcd938x_priv *wcd938x, struct device return dev_err_probe(dev, wcd938x->reset_gpio, "Failed to get reset gpio\n"); - wcd938x->us_euro_gpio = devm_gpiod_get_optional(dev, "us-euro", - GPIOD_OUT_LOW); - if (IS_ERR(wcd938x->us_euro_gpio)) - return dev_err_probe(dev, PTR_ERR(wcd938x->us_euro_gpio), - "us-euro swap Control GPIO not found\n"); + wcd938x->us_euro_mux = devm_mux_control_get(dev, NULL); + if (IS_ERR(wcd938x->us_euro_mux)) { + if (PTR_ERR(wcd938x->us_euro_mux) == -EPROBE_DEFER) + return -EPROBE_DEFER; + + /* mux is optional and now fallback to using gpio */ + wcd938x->us_euro_mux = NULL; + wcd938x->us_euro_gpio = devm_gpiod_get_optional(dev, "us-euro", GPIOD_OUT_LOW); + if (IS_ERR(wcd938x->us_euro_gpio)) + return dev_err_probe(dev, PTR_ERR(wcd938x->us_euro_gpio), + "us-euro swap Control GPIO not found\n"); + } else { + ret = mux_control_try_select(wcd938x->us_euro_mux, wcd938x->mux_state); + if (ret) { + dev_err(dev, "Error (%d) Unable to select us/euro mux state\n", ret); + wcd938x->mux_setup_done = false; + return ret; + } + wcd938x->mux_setup_done = true; + } cfg->swap_gnd_mic = wcd938x_swap_gnd_mic; @@ -3576,6 +3606,9 @@ static void wcd938x_remove(struct platform_device *pdev) pm_runtime_set_suspended(dev); pm_runtime_dont_use_autosuspend(dev); + if (wcd938x->us_euro_mux && wcd938x->mux_setup_done) + mux_control_deselect(wcd938x->us_euro_mux); + regulator_bulk_disable(WCD938X_MAX_SUPPLY, wcd938x->supplies); regulator_bulk_free(WCD938X_MAX_SUPPLY, wcd938x->supplies); } |