aboutsummaryrefslogtreecommitdiff
path: root/sound/soc/codecs/wm5110.c
diff options
context:
space:
mode:
authorGravatar Mark Brown <broonie@kernel.org> 2016-01-11 13:54:29 +0000
committerGravatar Mark Brown <broonie@kernel.org> 2016-01-11 13:54:29 +0000
commitfffe9b89d808782a7370b0f70c7271a9f65a261c (patch)
treef6f78cb27dcab1ef739da97508421feb72079f22 /sound/soc/codecs/wm5110.c
parentMerge remote-tracking branch 'asoc/topic/intel' into asoc-next (diff)
parentMerge remote-tracking branch 'asoc/topic/rt5677' into asoc-next (diff)
downloadlinux-fffe9b89d808782a7370b0f70c7271a9f65a261c.tar.gz
linux-fffe9b89d808782a7370b0f70c7271a9f65a261c.tar.bz2
linux-fffe9b89d808782a7370b0f70c7271a9f65a261c.zip
Merge tag 'asoc-v4.5' into asoc-next
ASoC: Updates for v4.5 This is quite a busy release on the driver front with a lot of new drivers being added but comparatively quiet on the core side with only one big change going in and that a fairly straightforward refactoring. - Conversion of the array of DAI links to a list by Mengdong Lin, supporting dynamically adding and removing DAI links. - Some more fixes for the topology code, though it is still not final and ready for enabling in production. We really need to get to the point where that can be done. - A pile of changes for Intel SkyLake drivers which hopefully deliver some useful initial functionality for systems with this chipset, though there is more work still to come. - New drivers for a number of Imagination Technologies IPs. - Lots of new features and cleanups for the Renesas drivers. - ANC support for WM5110. - New driver for Atmel class D speaker drivers. - New drivers for Cirrus CS47L24 and WM1831. - New driver for Dialog DA7128. - New drivers for Realtek RT5659 and RT56156. - New driver for Rockchip RK3036. - New driver for TI PC3168A # gpg: Signature made Wed 23 Dec 2015 00:42:40 GMT using RSA key ID 5D5487D0 # gpg: Good signature from "Mark Brown <broonie@sirena.org.uk>" # gpg: aka "Mark Brown <broonie@debian.org>" # gpg: aka "Mark Brown <broonie@kernel.org>" # gpg: aka "Mark Brown <broonie@tardis.ed.ac.uk>" # gpg: aka "Mark Brown <broonie@linaro.org>" # gpg: aka "Mark Brown <Mark.Brown@linaro.org>" # gpg: WARNING: This key is not certified with a trusted signature! # gpg: There is no indication that the signature belongs to the owner. # Primary key fingerprint: 3F25 68AA C269 98F9 E813 A1C5 C3F4 36CA 30F5 D8EB # Subkey fingerprint: ADE6 68AA 6757 18B5 9FE2 9FEA 24D6 8B72 5D54 87D0
Diffstat (limited to 'sound/soc/codecs/wm5110.c')
-rw-r--r--sound/soc/codecs/wm5110.c206
1 files changed, 205 insertions, 1 deletions
diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c
index 52b9ccf6d389..8d3b20ac7e30 100644
--- a/sound/soc/codecs/wm5110.c
+++ b/sound/soc/codecs/wm5110.c
@@ -573,6 +573,33 @@ static DECLARE_TLV_DB_SCALE(ng_tlv, -10200, 600, 0);
SOC_SINGLE(name " NG SPKDAT2L Switch", base, 10, 1, 0), \
SOC_SINGLE(name " NG SPKDAT2R Switch", base, 11, 1, 0)
+#define WM5110_RXANC_INPUT_ROUTES(widget, name) \
+ { widget, NULL, name " NG Mux" }, \
+ { name " NG Internal", NULL, "RXANC NG Clock" }, \
+ { name " NG Internal", NULL, name " Channel" }, \
+ { name " NG External", NULL, "RXANC NG External Clock" }, \
+ { name " NG External", NULL, name " Channel" }, \
+ { name " NG Mux", "None", name " Channel" }, \
+ { name " NG Mux", "Internal", name " NG Internal" }, \
+ { name " NG Mux", "External", name " NG External" }, \
+ { name " Channel", "Left", name " Left Input" }, \
+ { name " Channel", "Combine", name " Left Input" }, \
+ { name " Channel", "Right", name " Right Input" }, \
+ { name " Channel", "Combine", name " Right Input" }, \
+ { name " Left Input", "IN1", "IN1L PGA" }, \
+ { name " Right Input", "IN1", "IN1R PGA" }, \
+ { name " Left Input", "IN2", "IN2L PGA" }, \
+ { name " Right Input", "IN2", "IN2R PGA" }, \
+ { name " Left Input", "IN3", "IN3L PGA" }, \
+ { name " Right Input", "IN3", "IN3R PGA" }, \
+ { name " Left Input", "IN4", "IN4L PGA" }, \
+ { name " Right Input", "IN4", "IN4R PGA" }
+
+#define WM5110_RXANC_OUTPUT_ROUTES(widget, name) \
+ { widget, NULL, name " ANC Source" }, \
+ { name " ANC Source", "RXANCL", "RXANCL" }, \
+ { name " ANC Source", "RXANCR", "RXANCR" }
+
static const struct snd_kcontrol_new wm5110_snd_controls[] = {
SOC_ENUM("IN1 OSR", arizona_in_dmic_osr[0]),
SOC_ENUM("IN2 OSR", arizona_in_dmic_osr[1]),
@@ -637,6 +664,15 @@ SOC_SINGLE_TLV("IN4R Digital Volume", ARIZONA_ADC_DIGITAL_VOLUME_4R,
SOC_ENUM("Input Ramp Up", arizona_in_vi_ramp),
SOC_ENUM("Input Ramp Down", arizona_in_vd_ramp),
+SND_SOC_BYTES("RXANC Coefficients", ARIZONA_ANC_COEFF_START,
+ ARIZONA_ANC_COEFF_END - ARIZONA_ANC_COEFF_START + 1),
+SND_SOC_BYTES("RXANCL Config", ARIZONA_FCL_FILTER_CONTROL, 1),
+SND_SOC_BYTES("RXANCL Coefficients", ARIZONA_FCL_COEFF_START,
+ ARIZONA_FCL_COEFF_END - ARIZONA_FCL_COEFF_START + 1),
+SND_SOC_BYTES("RXANCR Config", ARIZONA_FCR_FILTER_CONTROL, 1),
+SND_SOC_BYTES("RXANCR Coefficients", ARIZONA_FCR_COEFF_START,
+ ARIZONA_FCR_COEFF_END - ARIZONA_FCR_COEFF_START + 1),
+
ARIZONA_MIXER_CONTROLS("EQ1", ARIZONA_EQ1MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ2", ARIZONA_EQ2MIX_INPUT_1_SOURCE),
ARIZONA_MIXER_CONTROLS("EQ3", ARIZONA_EQ3MIX_INPUT_1_SOURCE),
@@ -993,6 +1029,31 @@ static const struct soc_enum wm5110_aec_loopback =
static const struct snd_kcontrol_new wm5110_aec_loopback_mux =
SOC_DAPM_ENUM("AEC Loopback", wm5110_aec_loopback);
+static const struct snd_kcontrol_new wm5110_anc_input_mux[] = {
+ SOC_DAPM_ENUM("RXANCL Input", arizona_anc_input_src[0]),
+ SOC_DAPM_ENUM("RXANCL Channel", arizona_anc_input_src[1]),
+ SOC_DAPM_ENUM("RXANCR Input", arizona_anc_input_src[2]),
+ SOC_DAPM_ENUM("RXANCR Channel", arizona_anc_input_src[3]),
+};
+
+static const struct snd_kcontrol_new wm5110_anc_ng_mux =
+ SOC_DAPM_ENUM("RXANC NG Source", arizona_anc_ng_enum);
+
+static const struct snd_kcontrol_new wm5110_output_anc_src[] = {
+ SOC_DAPM_ENUM("HPOUT1L ANC Source", arizona_output_anc_src[0]),
+ SOC_DAPM_ENUM("HPOUT1R ANC Source", arizona_output_anc_src[1]),
+ SOC_DAPM_ENUM("HPOUT2L ANC Source", arizona_output_anc_src[2]),
+ SOC_DAPM_ENUM("HPOUT2R ANC Source", arizona_output_anc_src[3]),
+ SOC_DAPM_ENUM("HPOUT3L ANC Source", arizona_output_anc_src[4]),
+ SOC_DAPM_ENUM("HPOUT3R ANC Source", arizona_output_anc_src[5]),
+ SOC_DAPM_ENUM("SPKOUTL ANC Source", arizona_output_anc_src[6]),
+ SOC_DAPM_ENUM("SPKOUTR ANC Source", arizona_output_anc_src[7]),
+ SOC_DAPM_ENUM("SPKDAT1L ANC Source", arizona_output_anc_src[8]),
+ SOC_DAPM_ENUM("SPKDAT1R ANC Source", arizona_output_anc_src[9]),
+ SOC_DAPM_ENUM("SPKDAT2L ANC Source", arizona_output_anc_src[10]),
+ SOC_DAPM_ENUM("SPKDAT2R ANC Source", arizona_output_anc_src[11]),
+};
+
static const struct snd_soc_dapm_widget wm5110_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("SYSCLK", ARIZONA_SYSTEM_CLOCK_1, ARIZONA_SYSCLK_ENA_SHIFT,
0, wm5110_sysclk_ev, SND_SOC_DAPM_POST_PMU),
@@ -1183,6 +1244,65 @@ SND_SOC_DAPM_MUX("AEC Loopback", ARIZONA_DAC_AEC_CONTROL_1,
ARIZONA_AEC_LOOPBACK_ENA_SHIFT, 0,
&wm5110_aec_loopback_mux),
+SND_SOC_DAPM_SUPPLY("RXANC NG External Clock", SND_SOC_NOPM,
+ ARIZONA_EXT_NG_SEL_SET_SHIFT, 0, arizona_anc_ev,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA("RXANCL NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("RXANCR NG External", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_SUPPLY("RXANC NG Clock", SND_SOC_NOPM,
+ ARIZONA_CLK_NG_ENA_SET_SHIFT, 0, arizona_anc_ev,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA("RXANCL NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
+SND_SOC_DAPM_PGA("RXANCR NG Internal", SND_SOC_NOPM, 0, 0, NULL, 0),
+
+SND_SOC_DAPM_MUX("RXANCL Left Input", SND_SOC_NOPM, 0, 0,
+ &wm5110_anc_input_mux[0]),
+SND_SOC_DAPM_MUX("RXANCL Right Input", SND_SOC_NOPM, 0, 0,
+ &wm5110_anc_input_mux[0]),
+SND_SOC_DAPM_MUX("RXANCL Channel", SND_SOC_NOPM, 0, 0,
+ &wm5110_anc_input_mux[1]),
+SND_SOC_DAPM_MUX("RXANCL NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux),
+SND_SOC_DAPM_MUX("RXANCR Left Input", SND_SOC_NOPM, 0, 0,
+ &wm5110_anc_input_mux[2]),
+SND_SOC_DAPM_MUX("RXANCR Right Input", SND_SOC_NOPM, 0, 0,
+ &wm5110_anc_input_mux[2]),
+SND_SOC_DAPM_MUX("RXANCR Channel", SND_SOC_NOPM, 0, 0,
+ &wm5110_anc_input_mux[3]),
+SND_SOC_DAPM_MUX("RXANCR NG Mux", SND_SOC_NOPM, 0, 0, &wm5110_anc_ng_mux),
+
+SND_SOC_DAPM_PGA_E("RXANCL", SND_SOC_NOPM, ARIZONA_CLK_L_ENA_SET_SHIFT,
+ 0, NULL, 0, arizona_anc_ev,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+SND_SOC_DAPM_PGA_E("RXANCR", SND_SOC_NOPM, ARIZONA_CLK_R_ENA_SET_SHIFT,
+ 0, NULL, 0, arizona_anc_ev,
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD),
+
+SND_SOC_DAPM_MUX("HPOUT1L ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[0]),
+SND_SOC_DAPM_MUX("HPOUT1R ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[1]),
+SND_SOC_DAPM_MUX("HPOUT2L ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[2]),
+SND_SOC_DAPM_MUX("HPOUT2R ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[3]),
+SND_SOC_DAPM_MUX("HPOUT3L ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[4]),
+SND_SOC_DAPM_MUX("HPOUT3R ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[5]),
+SND_SOC_DAPM_MUX("SPKOUTL ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[6]),
+SND_SOC_DAPM_MUX("SPKOUTR ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[7]),
+SND_SOC_DAPM_MUX("SPKDAT1L ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[8]),
+SND_SOC_DAPM_MUX("SPKDAT1R ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[9]),
+SND_SOC_DAPM_MUX("SPKDAT2L ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[10]),
+SND_SOC_DAPM_MUX("SPKDAT2R ANC Source", SND_SOC_NOPM, 0, 0,
+ &wm5110_output_anc_src[11]),
+
SND_SOC_DAPM_AIF_OUT("AIF1TX1", NULL, 0,
ARIZONA_AIF1_TX_ENABLES, ARIZONA_AIF1TX1_ENA_SHIFT, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX2", NULL, 0,
@@ -1688,6 +1808,9 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
{ "Slim2 Capture", NULL, "SYSCLK" },
{ "Slim3 Capture", NULL, "SYSCLK" },
+ { "Voice Control DSP", NULL, "DSP3" },
+ { "Voice Control DSP", NULL, "SYSCLK" },
+
{ "IN1L PGA", NULL, "IN1L" },
{ "IN1R PGA", NULL, "IN1R" },
@@ -1836,6 +1959,22 @@ static const struct snd_soc_dapm_route wm5110_dapm_routes[] = {
{ "SPKDAT2L", NULL, "OUT6L" },
{ "SPKDAT2R", NULL, "OUT6R" },
+ WM5110_RXANC_INPUT_ROUTES("RXANCL", "RXANCL"),
+ WM5110_RXANC_INPUT_ROUTES("RXANCR", "RXANCR"),
+
+ WM5110_RXANC_OUTPUT_ROUTES("OUT1L", "HPOUT1L"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT1R", "HPOUT1R"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT2L", "HPOUT2L"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT2R", "HPOUT2R"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT3L", "HPOUT3L"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT3R", "HPOUT3R"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT4L", "SPKOUTL"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT4R", "SPKOUTR"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT5L", "SPKDAT1L"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT5R", "SPKDAT1R"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT6L", "SPKDAT2L"),
+ WM5110_RXANC_OUTPUT_ROUTES("OUT6R", "SPKDAT2R"),
+
{ "MICSUPP", NULL, "SYSCLK" },
{ "DRC1 Signal Activity", NULL, "DRC1L" },
@@ -1994,8 +2133,48 @@ static struct snd_soc_dai_driver wm5110_dai[] = {
},
.ops = &arizona_simple_dai_ops,
},
+ {
+ .name = "wm5110-cpu-voicectrl",
+ .capture = {
+ .stream_name = "Voice Control CPU",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = WM5110_RATES,
+ .formats = WM5110_FORMATS,
+ },
+ .compress_new = snd_soc_new_compress,
+ },
+ {
+ .name = "wm5110-dsp-voicectrl",
+ .capture = {
+ .stream_name = "Voice Control DSP",
+ .channels_min = 1,
+ .channels_max = 1,
+ .rates = WM5110_RATES,
+ .formats = WM5110_FORMATS,
+ },
+ },
};
+static int wm5110_open(struct snd_compr_stream *stream)
+{
+ struct snd_soc_pcm_runtime *rtd = stream->private_data;
+ struct wm5110_priv *priv = snd_soc_codec_get_drvdata(rtd->codec);
+ struct arizona *arizona = priv->core.arizona;
+ int n_adsp;
+
+ if (strcmp(rtd->codec_dai->name, "wm5110-dsp-voicectrl") == 0) {
+ n_adsp = 2;
+ } else {
+ dev_err(arizona->dev,
+ "No suitable compressed stream for DAI '%s'\n",
+ rtd->codec_dai->name);
+ return -EINVAL;
+ }
+
+ return wm_adsp_compr_open(&priv->core.adsp[n_adsp], stream);
+}
+
static int wm5110_codec_probe(struct snd_soc_codec *codec)
{
struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec);
@@ -2086,6 +2265,18 @@ static struct snd_soc_codec_driver soc_codec_dev_wm5110 = {
.num_dapm_routes = ARRAY_SIZE(wm5110_dapm_routes),
};
+static struct snd_compr_ops wm5110_compr_ops = {
+ .open = wm5110_open,
+ .free = wm_adsp_compr_free,
+ .set_params = wm_adsp_compr_set_params,
+ .get_caps = wm_adsp_compr_get_caps,
+ .trigger = wm_adsp_compr_trigger,
+};
+
+static struct snd_soc_platform_driver wm5110_compr_platform = {
+ .compr_ops = &wm5110_compr_ops,
+};
+
static int wm5110_probe(struct platform_device *pdev)
{
struct arizona *arizona = dev_get_drvdata(pdev->dev.parent);
@@ -2146,8 +2337,21 @@ static int wm5110_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
pm_runtime_idle(&pdev->dev);
- return snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
+ ret = snd_soc_register_platform(&pdev->dev, &wm5110_compr_platform);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register platform: %d\n", ret);
+ goto error;
+ }
+
+ ret = snd_soc_register_codec(&pdev->dev, &soc_codec_dev_wm5110,
wm5110_dai, ARRAY_SIZE(wm5110_dai));
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to register codec: %d\n", ret);
+ snd_soc_unregister_platform(&pdev->dev);
+ }
+
+error:
+ return ret;
}
static int wm5110_remove(struct platform_device *pdev)