sound/soc/fsl/fsl_sai.c
Source file repositories/reference/linux-study-clean/sound/soc/fsl/fsl_sai.c
File Facts
- System
- Linux kernel
- Corpus path
sound/soc/fsl/fsl_sai.c- Extension
.c- Size
- 55513 bytes
- Lines
- 2003
- Domain
- Driver Families
- Bucket
- sound/soc
- Inferred role
- Driver Families: implementation source
- Status
- source implementation candidate
Why This File Exists
Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.
- Touches IRQ or DMA behavior; this matters for the representative real-device path.
- Allocates kernel memory; connect allocation flags and lifetime to context constraints.
- Defines or uses C structs; map object ownership, embedded links, reference counts, and lock ownership.
Dependency Surface
linux/clk.hlinux/delay.hlinux/dmaengine.hlinux/firmware/imx/sm.hlinux/module.hlinux/of.hlinux/pinctrl/consumer.hlinux/pm_qos.hlinux/pm_runtime.hlinux/regmap.hlinux/slab.hlinux/time.hsound/core.hsound/dmaengine_pcm.hsound/pcm_params.hlinux/mfd/syscon.hlinux/mfd/syscon/imx6q-iomuxc-gpr.hfsl_sai.hfsl_utils.himx-pcm.h
Detected Declarations
function fsl_sai_dir_is_syncedfunction fsl_sai_isrfunction fsl_sai_set_dai_tdm_slot_txfunction fsl_sai_set_dai_tdm_slot_rxfunction fsl_sai_set_dai_tdm_slotfunction fsl_sai_xlate_tdm_slot_maskfunction fsl_sai_set_dai_bclk_ratiofunction fsl_sai_set_dai_sysclk_trfunction fsl_sai_set_mclk_ratefunction fsl_sai_set_dai_sysclkfunction fsl_sai_set_dai_fmt_trfunction fsl_sai_set_dai_fmtfunction fsl_sai_set_dai_fmt_txfunction fsl_sai_set_dai_fmt_rxfunction fsl_sai_set_bclkfunction fsl_sai_hw_paramsfunction Txfunction fsl_sai_hw_freefunction fsl_sai_config_disablefunction fsl_sai_triggerfunction fsl_sai_startupfunction fsl_sai_dai_probefunction fsl_sai_dai_resumefunction fsl_sai_component_probefunction fsl_sai_readable_regfunction fsl_sai_volatile_regfunction fsl_sai_writeable_regfunction fsl_sai_check_versionfunction fsl_sai_reset_hwfunction fsl_sai_calc_dl_offfunction I2Sfunction fsl_sai_probefunction snd_soc_add_pcm_runtimefunction fsl_sai_removefunction fsl_sai_runtime_suspendfunction fsl_sai_runtime_resume
Annotated Snippet
if (diff < bestdiff) {
savediv = ratio;
sai->mclk_id[tx] = id;
bestdiff = diff;
}
if (diff == 0)
break;
}
if (savediv == 0) {
dev_err(dai->dev, "failed to derive required %cx rate: %d\n",
tx ? 'T' : 'R', freq);
return -EINVAL;
}
dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n",
sai->mclk_id[tx], savediv, bestdiff);
/*
* 1) For Asynchronous mode, we must set RCR2 register for capture, and
* set TCR2 register for playback.
* 2) For Tx sync with Rx clock, we must set RCR2 register for playback
* and capture.
* 3) For Rx sync with Tx clock, we must set TCR2 register for playback
* and capture.
* 4) For Tx and Rx are both Synchronous with another SAI, we just
* ignore it.
*/
if (fsl_sai_dir_is_synced(sai, adir))
reg = FSL_SAI_xCR2(!tx, ofs);
else if (!sai->synchronous[dir])
reg = FSL_SAI_xCR2(tx, ofs);
else
return 0;
regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_MSEL_MASK,
FSL_SAI_CR2_MSEL(sai->mclk_id[tx]));
if (savediv == 1) {
regmap_update_bits(sai->regmap, reg,
FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP,
FSL_SAI_CR2_BYP);
if (fsl_sai_dir_is_synced(sai, adir))
regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
FSL_SAI_CR2_BCI, FSL_SAI_CR2_BCI);
else
regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs),
FSL_SAI_CR2_BCI, 0);
} else {
regmap_update_bits(sai->regmap, reg,
FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP,
savediv / 2 - 1);
}
return 0;
}
static int fsl_sai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *cpu_dai)
{
struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai);
unsigned int ofs = sai->soc_data->reg_offset;
bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK;
unsigned int channels = params_channels(params);
struct snd_dmaengine_dai_dma_data *dma_params;
struct fsl_sai_dl_cfg *dl_cfg = sai->dl_cfg;
u32 word_width = params_width(params);
int trce_mask = 0, dl_cfg_idx = 0;
int dl_cfg_cnt = sai->dl_cfg_cnt;
u32 dl_type = FSL_SAI_DL_I2S;
u32 val_cr4 = 0, val_cr5 = 0;
u32 slots = (channels == 1) ? 2 : channels;
u32 slot_width = word_width;
int adir = tx ? RX : TX;
u32 pins, bclk;
u32 watermark;
int ret, i;
if (sai->slot_width[tx])
slot_width = sai->slot_width[tx];
if (sai->slots[tx])
slots = sai->slots[tx];
else if (sai->bclk_ratio)
slots = sai->bclk_ratio / slot_width;
pins = DIV_ROUND_UP(channels, slots);
Annotation
- Immediate include surface: `linux/clk.h`, `linux/delay.h`, `linux/dmaengine.h`, `linux/firmware/imx/sm.h`, `linux/module.h`, `linux/of.h`, `linux/pinctrl/consumer.h`, `linux/pm_qos.h`.
- Detected declarations: `function fsl_sai_dir_is_synced`, `function fsl_sai_isr`, `function fsl_sai_set_dai_tdm_slot_tx`, `function fsl_sai_set_dai_tdm_slot_rx`, `function fsl_sai_set_dai_tdm_slot`, `function fsl_sai_xlate_tdm_slot_mask`, `function fsl_sai_set_dai_bclk_ratio`, `function fsl_sai_set_dai_sysclk_tr`, `function fsl_sai_set_mclk_rate`, `function fsl_sai_set_dai_sysclk`.
- Atlas domain: Driver Families / sound/soc.
- Implementation status: source implementation candidate.
- IRQ or DMA behavior appears here, which is relevant to the selected PCIe/NVMe device path.
Implementation Notes
- This generated page is the file-by-file coverage layer; curated subsystem chapters should link here when they synthesize a multi-file control flow.
- Core OS pages should be promoted from atlas-only to deep-reviewed when they explain data structures, invariants, locking, lifecycle, and C implementation snippets.
- Driver-family pages are intentionally pattern-oriented unless they are part of the selected PCIe/NVMe representative device path.