/* Default DAI format without Master and Slave flag */ #define DAI_FMT_BASE (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF)
/** * struct codec_priv - CODEC private data * @mclk: Main clock of the CODEC * @mclk_freq: Clock rate of MCLK * @free_freq: Clock rate of MCLK for hw_free() * @mclk_id: MCLK (or main clock) id for set_sysclk() * @fll_id: FLL (or secordary clock) id for set_sysclk() * @pll_id: PLL id for set_pll()
*/ struct codec_priv { struct clk *mclk; unsignedlong mclk_freq; unsignedlong free_freq;
u32 mclk_id; int fll_id; int pll_id;
};
/** * struct cpu_priv - CPU private data * @sysclk_freq: SYSCLK rates for set_sysclk() * @sysclk_dir: SYSCLK directions for set_sysclk() * @sysclk_id: SYSCLK ids for set_sysclk() * @sysclk_ratio: SYSCLK ratio on sample rate * @slot_width: Slot width of each frame * @slot_num: Number of slots of each frame * * Note: [1] for tx and [0] for rx
*/ struct cpu_priv { unsignedlong sysclk_freq[2];
u32 sysclk_dir[2];
u32 sysclk_id[2];
u32 sysclk_ratio[2];
u32 slot_width;
u32 slot_num;
};
/** * struct fsl_asoc_card_priv - Freescale Generic ASOC card private data * @dai_link: DAI link structure including normal one and DPCM link * @hp_jack: Headphone Jack structure * @mic_jack: Microphone Jack structure * @pdev: platform device pointer * @codec_priv: CODEC private data * @cpu_priv: CPU private data * @card: ASoC card structure * @streams: Mask of current active streams * @sample_rate: Current sample rate * @sample_format: Current sample format * @asrc_rate: ASRC sample rate used by Back-Ends * @asrc_format: ASRC sample format used by Back-Ends * @dai_fmt: DAI format between CPU and CODEC * @name: Card name
*/
/* * This dapm route map exists for DPCM link only. * The other routes shall go through Device Tree. * * Note: keep all ASRC routes in the second half * to drop them easily for non-ASRC cases.
*/ staticconststruct snd_soc_dapm_route audio_map[] = { /* 1st half -- Normal DAPM routes */
{"Playback", NULL, "CPU-Playback"},
{"CPU-Capture", NULL, "Capture"}, /* 2nd half -- ASRC DAPM routes */
{"CPU-Playback", NULL, "ASRC-Playback"},
{"ASRC-Capture", NULL, "CPU-Capture"},
};
/* Add all possible widgets into here without being redundant */ staticconststruct snd_soc_dapm_widget fsl_asoc_card_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Line Out Jack", NULL),
SND_SOC_DAPM_LINE("Line In Jack", NULL),
SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_SPK("Ext Spk", NULL),
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("AMIC", NULL),
SND_SOC_DAPM_MIC("DMIC", NULL),
};
/* Specific configurations of DAIs starts from here */
ret = snd_soc_dai_set_sysclk(snd_soc_rtd_to_cpu(rtd, 0), cpu_priv->sysclk_id[tx],
sysclk_freq,
cpu_priv->sysclk_dir[tx]); if (ret && ret != -ENOTSUPP) {
dev_err(dev, "failed to set sysclk for cpu dai\n"); goto fail;
}
if (cpu_priv->slot_width) { if (!cpu_priv->slot_num)
cpu_priv->slot_num = 2;
ret = snd_soc_dai_set_tdm_slot(snd_soc_rtd_to_cpu(rtd, 0), 0x3, 0x3,
cpu_priv->slot_num,
cpu_priv->slot_width); if (ret && ret != -ENOTSUPP) {
dev_err(dev, "failed to set TDM slot for cpu dai\n"); goto fail;
}
}
/* Specific configuration for PLL */
for_each_rtd_codec_dais(rtd, codec_idx, codec_dai) {
codec_priv = &priv->codec_priv[codec_idx];
if (!priv->streams && codec_priv->pll_id >= 0 && codec_priv->fll_id >= 0) { /* Force freq to be free_freq to avoid error message in codec */
ret = snd_soc_dai_set_sysclk(codec_dai,
codec_priv->mclk_id,
codec_priv->free_freq,
SND_SOC_CLOCK_IN); if (ret) {
dev_err(dev, "failed to switch away from FLL: %d\n", ret); return ret;
}
ret = snd_soc_dai_set_pll(codec_dai,
codec_priv->pll_id, 0, 0, 0); if (ret && ret != -ENOTSUPP) {
dev_err(dev, "failed to stop FLL: %d\n", ret); return ret;
}
}
}
/* * Use slots 3/4 for S/PDIF so SSI won't try to enable * other slots and send some samples there * due to SLOTREQ bits for S/PDIF received from codec
*/
snd_ac97_update_bits(ac97, AC97_EXTENDED_STATUS,
AC97_EA_SPSA_SLOT_MASK, AC97_EA_SPSA_3_4); #endif
ret = snd_soc_dai_set_sysclk(codec_dai, codec_priv->mclk_id,
codec_priv->mclk_freq, SND_SOC_CLOCK_IN); if (ret && ret != -ENOTSUPP) {
dev_err(dev, "failed to set sysclk in %s\n", __func__); return ret;
}
if (!IS_ERR_OR_NULL(codec_priv->mclk))
clk_prepare_enable(codec_priv->mclk);
}
priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL); if (!priv) return -ENOMEM;
priv->pdev = pdev;
cpu_np = of_parse_phandle(np, "audio-cpu", 0); /* Give a chance to old DT bindings */ if (!cpu_np)
cpu_np = of_parse_phandle(np, "ssi-controller", 0); if (!cpu_np)
cpu_np = of_parse_phandle(np, "spdif-controller", 0); if (!cpu_np) {
dev_err(&pdev->dev, "CPU phandle missing or invalid\n");
ret = -EINVAL; goto fail;
}
cpu_pdev = of_find_device_by_node(cpu_np); if (!cpu_pdev) {
dev_err(&pdev->dev, "failed to find CPU DAI device\n");
ret = -EINVAL; goto fail;
}
asrc_np = of_parse_phandle(np, "audio-asrc", 0); if (asrc_np)
asrc_pdev = of_find_device_by_node(asrc_np);
/* Get the MCLK rate only, and leave it controlled by CODEC drivers */ for (codec_idx = 0; codec_idx < 2; codec_idx++) { if (codec_dev[codec_idx]) { struct clk *codec_clk = clk_get(codec_dev[codec_idx], NULL);
if (!IS_ERR(codec_clk)) {
priv->codec_priv[codec_idx].mclk_freq = clk_get_rate(codec_clk);
clk_put(codec_clk);
}
}
}
/* Default sample rate and format, will be updated in hw_params() */
priv->sample_rate = 44100;
priv->sample_format = SNDRV_PCM_FORMAT_S16_LE;
/* Assign a default DAI format, and allow each card to overwrite it */
priv->dai_fmt = DAI_FMT_BASE;
/* * Allow setting mclk-id from the device-tree node. Otherwise, the * default value for each card configuration is used.
*/
for_each_link_codecs((&(priv->dai_link[0])), codec_idx, codec_comp) {
of_property_read_u32_index(np, "mclk-id", codec_idx,
&priv->codec_priv[codec_idx].mclk_id);
}
/* Format info from DT is optional. */
snd_soc_daifmt_parse_clock_provider_as_phandle(np, NULL, &bitclkprovider, &frameprovider); if (bitclkprovider || frameprovider) { unsignedint daifmt = snd_soc_daifmt_parse_format(np, NULL); bool codec_bitclkprovider = false; bool codec_frameprovider = false;
/* Override dai_fmt with value from DT */
priv->dai_fmt = daifmt;
}
/* Change direction according to format */ if (priv->dai_fmt & SND_SOC_DAIFMT_CBP_CFP) {
priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_IN;
priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_IN;
}
if (!fsl_asoc_card_is_ac97(priv) && !codec_dev[0]
&& codec_dai_name[0] != snd_soc_dummy_dlc.dai_name) {
dev_dbg(&pdev->dev, "failed to find codec device\n");
ret = -EPROBE_DEFER; goto asrc_fail;
}
/* Common settings for corresponding Freescale CPU DAI driver */ if (of_node_name_eq(cpu_np, "ssi")) { /* Only SSI needs to configure AUDMUX */
ret = fsl_asoc_card_audmux_init(np, priv); if (ret) {
dev_err(&pdev->dev, "failed to init audmux\n"); goto asrc_fail;
}
} elseif (of_node_name_eq(cpu_np, "esai")) { struct clk *esai_clk = clk_get(&cpu_pdev->dev, "extal");
ret = of_property_read_u32(asrc_np, "fsl,asrc-rate",
&priv->asrc_rate); if (ret) {
dev_err(&pdev->dev, "failed to get output rate\n");
ret = -EINVAL; goto asrc_fail;
}
ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &asrc_fmt);
priv->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { /* Fallback to old binding; translate to asrc_format */
ret = of_property_read_u32(asrc_np, "fsl,asrc-width",
&width); if (ret) {
dev_err(&pdev->dev, "failed to decide output format\n"); goto asrc_fail;
}
ret = devm_snd_soc_register_card(&pdev->dev, &priv->card); if (ret) {
dev_err_probe(&pdev->dev, ret, "snd_soc_register_card failed\n"); goto asrc_fail;
}
/* * Properties "hp-det-gpios" and "mic-det-gpios" are optional, and * simple_util_init_jack() uses these properties for creating * Headphone Jack and Microphone Jack. * * The notifier is initialized in snd_soc_card_jack_new(), then * snd_soc_jack_notifier_register can be called.
*/ if (of_property_read_bool(np, "hp-det-gpios") ||
of_property_read_bool(np, "hp-det-gpio") /* deprecated */) {
ret = simple_util_init_jack(&priv->card, &priv->hp_jack,
1, NULL, "Headphone Jack"); if (ret) goto asrc_fail;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.