X-Git-Url: http://git.cascardo.eti.br/?a=blobdiff_plain;f=sound%2Fsoc%2Fcodecs%2Fwm5110.c;fp=sound%2Fsoc%2Fcodecs%2Fwm5110.c;h=97c0f1e2388637dcdc686da1f1a5cf06037a6944;hb=f11aec0d7c835c3b83e74e3fd60d2e48a850c857;hp=c04c0bc6f58ad434de2bbe5825be1b41182b1c24;hpb=2256b8d2ff6c8e994161ab15b6e6d0314d3174ae;p=cascardo%2Flinux.git diff --git a/sound/soc/codecs/wm5110.c b/sound/soc/codecs/wm5110.c index c04c0bc6f58a..97c0f1e23886 100644 --- a/sound/soc/codecs/wm5110.c +++ b/sound/soc/codecs/wm5110.c @@ -360,15 +360,13 @@ static int wm5110_hp_ev(struct snd_soc_dapm_widget *w, static int wm5110_clear_pga_volume(struct arizona *arizona, int output) { - struct reg_sequence clear_pga = { - ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4, 0x80 - }; + unsigned int reg = ARIZONA_OUTPUT_PATH_CONFIG_1L + output * 4; int ret; - ret = regmap_multi_reg_write_bypassed(arizona->regmap, &clear_pga, 1); + ret = regmap_write(arizona->regmap, reg, 0x80); if (ret) dev_err(arizona->dev, "Failed to clear PGA (0x%x): %d\n", - clear_pga.reg, ret); + reg, ret); return ret; } @@ -439,18 +437,17 @@ static int wm5110_in_pga_get(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct snd_soc_card *card = dapm->card; int ret; /* * PGA Volume is also used as part of the enable sequence, so * usage of it should be avoided whilst that is running. */ - mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + snd_soc_dapm_mutex_lock(dapm); ret = snd_soc_get_volsw_range(kcontrol, ucontrol); - mutex_unlock(&card->dapm_mutex); + snd_soc_dapm_mutex_unlock(dapm); return ret; } @@ -460,18 +457,17 @@ static int wm5110_in_pga_put(struct snd_kcontrol *kcontrol, { struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol); struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); - struct snd_soc_card *card = dapm->card; int ret; /* * PGA Volume is also used as part of the enable sequence, so * usage of it should be avoided whilst that is running. */ - mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME); + snd_soc_dapm_mutex_lock(dapm); ret = snd_soc_put_volsw_range(kcontrol, ucontrol); - mutex_unlock(&card->dapm_mutex); + snd_soc_dapm_mutex_unlock(dapm); return ret; } @@ -575,6 +571,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]), @@ -639,6 +662,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), @@ -995,6 +1027,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), @@ -1185,6 +1242,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, @@ -1690,6 +1806,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" }, @@ -1838,6 +1957,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" }, @@ -1996,12 +2131,65 @@ 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 irqreturn_t wm5110_adsp2_irq(int irq, void *data) +{ + struct wm5110_priv *florida = data; + int ret; + + ret = wm_adsp_compr_handle_irq(&florida->core.adsp[2]); + if (ret == -ENODEV) + return IRQ_NONE; + + return IRQ_HANDLED; +} + static int wm5110_codec_probe(struct snd_soc_codec *codec) { struct snd_soc_dapm_context *dapm = snd_soc_codec_get_dapm(codec); struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->core.arizona; int i, ret; priv->core.arizona->dapm = dapm; @@ -2010,6 +2198,14 @@ static int wm5110_codec_probe(struct snd_soc_codec *codec) arizona_init_gpio(codec); arizona_init_mono(codec); + ret = arizona_request_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, + "ADSP2 Compressed IRQ", wm5110_adsp2_irq, + priv); + if (ret != 0) { + dev_err(codec->dev, "Failed to request DSP IRQ: %d\n", ret); + return ret; + } + for (i = 0; i < WM5110_NUM_ADSP; ++i) { ret = wm_adsp2_codec_probe(&priv->core.adsp[i], codec); if (ret) @@ -2030,12 +2226,15 @@ err_adsp2_codec_probe: for (--i; i >= 0; --i) wm_adsp2_codec_remove(&priv->core.adsp[i], codec); + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); + return ret; } static int wm5110_codec_remove(struct snd_soc_codec *codec) { struct wm5110_priv *priv = snd_soc_codec_get_drvdata(codec); + struct arizona *arizona = priv->core.arizona; int i; for (i = 0; i < WM5110_NUM_ADSP; ++i) @@ -2043,6 +2242,8 @@ static int wm5110_codec_remove(struct snd_soc_codec *codec) priv->core.arizona->dapm = NULL; + arizona_free_irq(arizona, ARIZONA_IRQ_DSP_IRQ1, priv); + return 0; } @@ -2088,6 +2289,20 @@ 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, + .pointer = wm_adsp_compr_pointer, + .copy = wm_adsp_compr_copy, +}; + +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); @@ -2148,12 +2363,26 @@ 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) { + snd_soc_unregister_platform(&pdev->dev); snd_soc_unregister_codec(&pdev->dev); pm_runtime_disable(&pdev->dev);