Lines Matching +full:codec +full:- +full:aif2 +full:- +full:bclk

1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * This driver supports the digital controls for the internal codec
6 * (C) Copyright 2010-2016
9 * Mylène Josserand <mylene.josserand@free-electrons.com>
23 #include <sound/soc-dapm.h>
200 regcache_cache_only(scodec->regmap, false); in sun8i_codec_runtime_resume()
202 ret = regcache_sync(scodec->regmap); in sun8i_codec_runtime_resume()
215 regcache_cache_only(scodec->regmap, true); in sun8i_codec_runtime_suspend()
216 regcache_mark_dirty(scodec->regmap); in sun8i_codec_runtime_suspend()
252 return -EINVAL; in sun8i_codec_get_hw_rate()
262 struct sun8i_codec_aif *aif = &scodec->aifs[i]; in sun8i_codec_update_sample_rate()
264 if (aif->active_streams) in sun8i_codec_update_sample_rate()
265 max_rate = max(max_rate, aif->sample_rate); in sun8i_codec_update_sample_rate()
268 /* Set the sample rate for ADC->DAC passthrough when no AIF is active. */ in sun8i_codec_update_sample_rate()
276 regmap_update_bits(scodec->regmap, SUN8I_SYS_SR_CTRL, in sun8i_codec_update_sample_rate()
290 case SND_SOC_DAIFMT_CBC_CFC: /* Codec slave, DAI master */ in sun8i_codec_set_fmt()
293 case SND_SOC_DAIFMT_CBP_CFP: /* Codec Master, DAI slave */ in sun8i_codec_set_fmt()
297 return -EINVAL; in sun8i_codec_set_fmt()
300 if (dai->id == SUN8I_CODEC_AIF3) { in sun8i_codec_set_fmt()
303 return -EINVAL; in sun8i_codec_set_fmt()
305 /* Use the AIF2 BCLK and LRCK for AIF3. */ in sun8i_codec_set_fmt()
306 regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), in sun8i_codec_set_fmt()
310 regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), in sun8i_codec_set_fmt()
335 return -EINVAL; in sun8i_codec_set_fmt()
338 if (dai->id == SUN8I_CODEC_AIF3) { in sun8i_codec_set_fmt()
341 return -EINVAL; in sun8i_codec_set_fmt()
343 regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), in sun8i_codec_set_fmt()
356 case SND_SOC_DAIFMT_IB_NF: /* Inverted BCLK */ in sun8i_codec_set_fmt()
363 return -EINVAL; in sun8i_codec_set_fmt()
369 return -EINVAL; in sun8i_codec_set_fmt()
375 * It appears that the DAI and the codec in the A33 SoC don't in sun8i_codec_set_fmt()
381 * that the codec probably gets it backward, and we have to in sun8i_codec_set_fmt()
384 invert ^= scodec->quirks->lrck_inversion; in sun8i_codec_set_fmt()
387 regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), in sun8i_codec_set_fmt()
399 struct sun8i_codec_aif *aif = &scodec->aifs[dai->id]; in sun8i_codec_set_tdm_slot()
402 return -EINVAL; in sun8i_codec_set_tdm_slot()
404 aif->slots = slots; in sun8i_codec_set_tdm_slot()
405 aif->slot_width = slot_width; in sun8i_codec_set_tdm_slot()
439 if (dai->id != SUN8I_CODEC_AIF1) in sun8i_codec_startup()
442 if (!scodec->sysclk_refcnt) in sun8i_codec_startup()
444 else if (scodec->sysclk_rate == 22579200) in sun8i_codec_startup()
446 else if (scodec->sysclk_rate == 24576000) in sun8i_codec_startup()
449 return -EINVAL; in sun8i_codec_startup()
451 return snd_pcm_hw_constraint_list(substream->runtime, 0, in sun8i_codec_startup()
487 if (bdiv->div == div) in sun8i_codec_get_bclk_div()
488 return bdiv->val; in sun8i_codec_get_bclk_div()
491 return -EINVAL; in sun8i_codec_get_bclk_div()
500 return -EINVAL; in sun8i_codec_get_lrck_div_order()
515 struct sun8i_codec_aif *aif = &scodec->aifs[dai->id]; in sun8i_codec_hw_params()
517 unsigned int slots = aif->slots ?: params_channels(params); in sun8i_codec_hw_params()
518 unsigned int slot_width = aif->slot_width ?: params_width(params); in sun8i_codec_hw_params()
538 return -EINVAL; in sun8i_codec_hw_params()
541 regmap_update_bits(scodec->regmap, SUN8I_AIF_CLK_CTRL(dai->id), in sun8i_codec_hw_params()
545 /* LRCK divider (BCLK/LRCK ratio) */ in sun8i_codec_hw_params()
550 if (dai->id == SUN8I_CODEC_AIF2 || dai->id == SUN8I_CODEC_AIF3) { in sun8i_codec_hw_params()
551 /* AIF2 and AIF3 share AIF2's BCLK and LRCK generation circuitry. */ in sun8i_codec_hw_params()
552 int partner = (SUN8I_CODEC_AIF2 + SUN8I_CODEC_AIF3) - dai->id; in sun8i_codec_hw_params()
553 const struct sun8i_codec_aif *partner_aif = &scodec->aifs[partner]; in sun8i_codec_hw_params()
556 if (partner_aif->open_streams && in sun8i_codec_hw_params()
557 (lrck_div_order != partner_aif->lrck_div_order || in sun8i_codec_hw_params()
558 sample_rate != partner_aif->sample_rate)) { in sun8i_codec_hw_params()
559 dev_err(dai->dev, in sun8i_codec_hw_params()
561 dai->name, partner_name); in sun8i_codec_hw_params()
562 return -EBUSY; in sun8i_codec_hw_params()
567 clk_reg = SUN8I_AIF_CLK_CTRL(dai->id); in sun8i_codec_hw_params()
570 regmap_update_bits(scodec->regmap, clk_reg, in sun8i_codec_hw_params()
572 (lrck_div_order - 4) << SUN8I_AIF_CLK_CTRL_LRCK_DIV); in sun8i_codec_hw_params()
574 /* BCLK divider (SYSCLK/BCLK ratio) */ in sun8i_codec_hw_params()
579 regmap_update_bits(scodec->regmap, clk_reg, in sun8i_codec_hw_params()
592 ret = (aif->open_streams ? clk_set_rate : clk_set_rate_exclusive)(scodec->clk_module, in sun8i_codec_hw_params()
594 if (ret == -EBUSY) in sun8i_codec_hw_params()
595 dev_err(dai->dev, in sun8i_codec_hw_params()
597 dai->name, sample_rate); in sun8i_codec_hw_params()
601 if (!aif->open_streams) in sun8i_codec_hw_params()
602 scodec->sysclk_refcnt++; in sun8i_codec_hw_params()
603 scodec->sysclk_rate = sysclk_rate; in sun8i_codec_hw_params()
605 aif->lrck_div_order = lrck_div_order; in sun8i_codec_hw_params()
606 aif->sample_rate = sample_rate; in sun8i_codec_hw_params()
607 aif->open_streams |= BIT(substream->stream); in sun8i_codec_hw_params()
616 struct sun8i_codec_aif *aif = &scodec->aifs[dai->id]; in sun8i_codec_hw_free()
619 if (aif->open_streams != BIT(substream->stream)) in sun8i_codec_hw_free()
622 clk_rate_exclusive_put(scodec->clk_module); in sun8i_codec_hw_free()
623 scodec->sysclk_refcnt--; in sun8i_codec_hw_free()
624 aif->lrck_div_order = 0; in sun8i_codec_hw_free()
625 aif->sample_rate = 0; in sun8i_codec_hw_free()
628 aif->open_streams &= ~BIT(substream->stream); in sun8i_codec_hw_free()
642 .name = "sun8i-codec-aif1",
667 .name = "sun8i-codec-aif2",
672 .stream_name = "AIF2 Capture",
681 .stream_name = "AIF2 Playback",
692 .name = "sun8i-codec-aif3",
718 static const DECLARE_TLV_DB_SCALE(sun8i_codec_vol_scale, -12000, 75, 1);
731 SOC_DOUBLE_TLV("AIF2 ADC Capture Volume",
736 SOC_DOUBLE_TLV("AIF2 DAC Playback Volume",
756 struct snd_soc_component *component = snd_soc_dapm_to_component(w->dapm); in sun8i_codec_aif_event()
758 struct sun8i_codec_aif *aif = &scodec->aifs[w->sname[3] - '1']; in sun8i_codec_aif_event()
759 int stream = w->id == snd_soc_dapm_aif_out; in sun8i_codec_aif_event()
762 aif->active_streams |= BIT(stream); in sun8i_codec_aif_event()
764 aif->active_streams &= ~BIT(stream); in sun8i_codec_aif_event()
790 SOC_DAPM_ENUM("AIF2 ADC Stereo Capture Route",
794 "None", "AIF2 ADCL", "AIF2 ADCR"
811 SOC_DAPM_DOUBLE("AIF2 Digital ADC Capture Switch",
819 SOC_DAPM_DOUBLE("AIF2 Inv Digital ADC Capture Switch",
826 SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA0 Capture Switch",
830 SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF1 DA1 Capture Switch",
834 SOC_DAPM_DOUBLE("AIF2 ADC Mixer AIF2 DAC Rev Capture Switch",
838 SOC_DAPM_DOUBLE("AIF2 ADC Mixer ADC Capture Switch",
845 "AIF2", "AIF3+2", "AIF2+3"
854 SOC_DAPM_ENUM("AIF2 DAC Source Playback Route",
874 SOC_DAPM_ENUM("AIF2 DAC Stereo Playback Route",
886 SOC_DAPM_DOUBLE("AIF2 Digital DAC Playback Switch", SUN8I_DAC_MXR_SRC,
912 SND_SOC_DAPM_SUPPLY("CLK AIF2",
929 SND_SOC_DAPM_SUPPLY("RST AIF2",
960 SND_SOC_DAPM_AIF_OUT_E("AIF2 ADCL", "AIF2 Capture", 0,
965 SND_SOC_DAPM_AIF_OUT("AIF2 ADCR", "AIF2 Capture", 1,
980 SND_SOC_DAPM_MUX("AIF2 ADCL Stereo Mux", SND_SOC_NOPM, 0, 0,
982 SND_SOC_DAPM_MUX("AIF2 ADCR Stereo Mux", SND_SOC_NOPM, 0, 0,
995 SOC_MIXER_ARRAY("AIF2 ADCL Mixer", SND_SOC_NOPM, 0, 0,
997 SOC_MIXER_ARRAY("AIF2 ADCR Mixer", SND_SOC_NOPM, 0, 0,
1001 SND_SOC_DAPM_MUX("AIF2 DACL Source", SND_SOC_NOPM, 0, 0,
1003 SND_SOC_DAPM_MUX("AIF2 DACR Source", SND_SOC_NOPM, 0, 0,
1012 SND_SOC_DAPM_MUX("AIF2 DACL Stereo Mux", SND_SOC_NOPM, 0, 0,
1014 SND_SOC_DAPM_MUX("AIF2 DACR Stereo Mux", SND_SOC_NOPM, 0, 0,
1027 SND_SOC_DAPM_AIF_IN_E("AIF2 DACL", "AIF2 Playback", 0,
1032 SND_SOC_DAPM_AIF_IN("AIF2 DACR", "AIF2 Playback", 1,
1041 /* ADC Inputs (connected to analog codec DAPM context) */
1045 /* DAC Outputs (connected to analog codec DAPM context) */
1070 { "CLK AIF2", NULL, "AIF2CLK" },
1071 { "CLK AIF2", NULL, "SYSCLK" },
1072 { "RST AIF2", NULL, "CLK AIF2" },
1073 { "AIF2 ADCL", NULL, "RST AIF2" },
1074 { "AIF2 ADCR", NULL, "RST AIF2" },
1075 { "AIF2 DACL", NULL, "RST AIF2" },
1076 { "AIF2 DACR", NULL, "RST AIF2" },
1100 { "AIF2 ADCL", NULL, "AIF2 ADCL Stereo Mux" },
1101 { "AIF2 ADCR", NULL, "AIF2 ADCR Stereo Mux" },
1120 { "AIF2 ADCL Stereo Mux", "Stereo", "AIF2 ADCL Mixer" },
1121 { "AIF2 ADCL Stereo Mux", "Reverse Stereo", "AIF2 ADCR Mixer" },
1122 { "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
1123 { "AIF2 ADCL Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
1124 { "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
1125 { "AIF2 ADCL Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
1127 { "AIF2 ADCR Stereo Mux", "Stereo", "AIF2 ADCR Mixer" },
1128 { "AIF2 ADCR Stereo Mux", "Reverse Stereo", "AIF2 ADCL Mixer" },
1129 { "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCL Mixer" },
1130 { "AIF2 ADCR Stereo Mux", "Sum Mono", "AIF2 ADCR Mixer" },
1131 { "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCL Mixer" },
1132 { "AIF2 ADCR Stereo Mux", "Mix Mono", "AIF2 ADCR Mixer" },
1135 { "AIF3 ADC Source Capture Route", "AIF2 ADCL", "AIF2 ADCL Mixer" },
1136 { "AIF3 ADC Source Capture Route", "AIF2 ADCR", "AIF2 ADCR Mixer" },
1140 { "AIF1 AD0L Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACL Source" },
1142 { "AIF1 AD0L Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACR Source" },
1145 { "AIF1 AD0R Mixer", "AIF2 Digital ADC Capture Switch", "AIF2 DACR Source" },
1147 { "AIF1 AD0R Mixer", "AIF2 Inv Digital ADC Capture Switch", "AIF2 DACL Source" },
1149 { "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0L Stereo Mux" },
1150 { "AIF2 ADCL Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACR Source" },
1151 { "AIF2 ADCL Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCL" },
1153 { "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF1 DA0 Capture Switch", "AIF1 DA0R Stereo Mux" },
1154 { "AIF2 ADCR Mixer", "AIF2 ADC Mixer AIF2 DAC Rev Capture Switch", "AIF2 DACL Source" },
1155 { "AIF2 ADCR Mixer", "AIF2 ADC Mixer ADC Capture Switch", "ADCR" },
1158 { "AIF2 DACL Source", "AIF2", "AIF2 DACL Stereo Mux" },
1159 { "AIF2 DACL Source", "AIF3+2", "AIF3 DAC" },
1160 { "AIF2 DACL Source", "AIF2+3", "AIF2 DACL Stereo Mux" },
1162 { "AIF2 DACR Source", "AIF2", "AIF2 DACR Stereo Mux" },
1163 { "AIF2 DACR Source", "AIF3+2", "AIF2 DACR Stereo Mux" },
1164 { "AIF2 DACR Source", "AIF2+3", "AIF3 DAC" },
1181 { "AIF2 DACL Stereo Mux", "Stereo", "AIF2 DACL" },
1182 { "AIF2 DACL Stereo Mux", "Reverse Stereo", "AIF2 DACR" },
1183 { "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACL" },
1184 { "AIF2 DACL Stereo Mux", "Sum Mono", "AIF2 DACR" },
1185 { "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACL" },
1186 { "AIF2 DACL Stereo Mux", "Mix Mono", "AIF2 DACR" },
1188 { "AIF2 DACR Stereo Mux", "Stereo", "AIF2 DACR" },
1189 { "AIF2 DACR Stereo Mux", "Reverse Stereo", "AIF2 DACL" },
1190 { "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACL" },
1191 { "AIF2 DACR Stereo Mux", "Sum Mono", "AIF2 DACR" },
1192 { "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACL" },
1193 { "AIF2 DACR Stereo Mux", "Mix Mono", "AIF2 DACR" },
1201 { "DACL Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACL Source" },
1205 { "DACR Mixer", "AIF2 Digital DAC Playback Switch", "AIF2 DACR Source" },
1210 /* Legacy ADC Inputs (connected to analog codec DAPM context) */
1214 /* Legacy DAC Outputs (connected to analog codec DAPM context) */
1236 if (scodec->quirks->legacy_widgets) { in sun8i_codec_component_probe()
1254 regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL, in sun8i_codec_component_probe()
1261 regmap_update_bits(scodec->regmap, SUN8I_SYSCLK_CTL, in sun8i_codec_component_probe()
1298 scodec = devm_kzalloc(&pdev->dev, sizeof(*scodec), GFP_KERNEL); in sun8i_codec_probe()
1300 return -ENOMEM; in sun8i_codec_probe()
1302 scodec->clk_module = devm_clk_get(&pdev->dev, "mod"); in sun8i_codec_probe()
1303 if (IS_ERR(scodec->clk_module)) { in sun8i_codec_probe()
1304 dev_err(&pdev->dev, "Failed to get the module clock\n"); in sun8i_codec_probe()
1305 return PTR_ERR(scodec->clk_module); in sun8i_codec_probe()
1310 dev_err(&pdev->dev, "Failed to map the registers\n"); in sun8i_codec_probe()
1314 scodec->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "bus", base, in sun8i_codec_probe()
1316 if (IS_ERR(scodec->regmap)) { in sun8i_codec_probe()
1317 dev_err(&pdev->dev, "Failed to create our regmap\n"); in sun8i_codec_probe()
1318 return PTR_ERR(scodec->regmap); in sun8i_codec_probe()
1321 scodec->quirks = of_device_get_match_data(&pdev->dev); in sun8i_codec_probe()
1325 pm_runtime_enable(&pdev->dev); in sun8i_codec_probe()
1326 if (!pm_runtime_enabled(&pdev->dev)) { in sun8i_codec_probe()
1327 ret = sun8i_codec_runtime_resume(&pdev->dev); in sun8i_codec_probe()
1332 ret = devm_snd_soc_register_component(&pdev->dev, &sun8i_soc_component, in sun8i_codec_probe()
1336 dev_err(&pdev->dev, "Failed to register codec\n"); in sun8i_codec_probe()
1343 if (!pm_runtime_status_suspended(&pdev->dev)) in sun8i_codec_probe()
1344 sun8i_codec_runtime_suspend(&pdev->dev); in sun8i_codec_probe()
1347 pm_runtime_disable(&pdev->dev); in sun8i_codec_probe()
1354 pm_runtime_disable(&pdev->dev); in sun8i_codec_remove()
1355 if (!pm_runtime_status_suspended(&pdev->dev)) in sun8i_codec_remove()
1356 sun8i_codec_runtime_suspend(&pdev->dev); in sun8i_codec_remove()
1368 { .compatible = "allwinner,sun8i-a33-codec", .data = &sun8i_a33_quirks },
1369 { .compatible = "allwinner,sun50i-a64-codec", .data = &sun50i_a64_quirks },
1381 .name = "sun8i-codec",
1390 MODULE_DESCRIPTION("Allwinner A33 (sun8i) codec driver");
1391 MODULE_AUTHOR("Mylène Josserand <mylene.josserand@free-electrons.com>");
1393 MODULE_ALIAS("platform:sun8i-codec");