Lines Matching +full:dai +full:- +full:tdm +full:- +full:slot +full:- +full:rx +full:- +full:mask

1 // SPDX-License-Identifier: (GPL-2.0 OR MIT)
11 #include <sound/soc-dai.h>
13 #include "axg-tdm.h"
23 static unsigned int axg_tdm_slots_total(u32 *mask) in axg_tdm_slots_total() argument
28 if (!mask) in axg_tdm_slots_total()
33 slots += hweight32(mask[i]); in axg_tdm_slots_total()
38 int axg_tdm_set_tdm_slots(struct snd_soc_dai *dai, u32 *tx_mask, in axg_tdm_set_tdm_slots() argument
42 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); in axg_tdm_set_tdm_slots()
43 struct axg_tdm_stream *tx = snd_soc_dai_dma_data_get_playback(dai); in axg_tdm_set_tdm_slots()
44 struct axg_tdm_stream *rx = snd_soc_dai_dma_data_get_capture(dai); in axg_tdm_set_tdm_slots() local
51 /* We should at least have a slot for a valid interface */ in axg_tdm_set_tdm_slots()
53 dev_err(dai->dev, "interface has no slot\n"); in axg_tdm_set_tdm_slots()
54 return -EINVAL; in axg_tdm_set_tdm_slots()
57 iface->slots = slots; in axg_tdm_set_tdm_slots()
77 dev_err(dai->dev, "unsupported slot width: %d\n", slot_width); in axg_tdm_set_tdm_slots()
78 return -EINVAL; in axg_tdm_set_tdm_slots()
81 iface->slot_width = slot_width; in axg_tdm_set_tdm_slots()
83 /* Amend the dai driver and let dpcm merge do its job */ in axg_tdm_set_tdm_slots()
85 tx->mask = tx_mask; in axg_tdm_set_tdm_slots()
86 dai->driver->playback.channels_max = tx_slots; in axg_tdm_set_tdm_slots()
87 dai->driver->playback.formats = fmt; in axg_tdm_set_tdm_slots()
90 if (rx) { in axg_tdm_set_tdm_slots()
91 rx->mask = rx_mask; in axg_tdm_set_tdm_slots()
92 dai->driver->capture.channels_max = rx_slots; in axg_tdm_set_tdm_slots()
93 dai->driver->capture.formats = fmt; in axg_tdm_set_tdm_slots()
100 static int axg_tdm_iface_set_sysclk(struct snd_soc_dai *dai, int clk_id, in axg_tdm_iface_set_sysclk() argument
103 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); in axg_tdm_iface_set_sysclk()
104 int ret = -ENOTSUPP; in axg_tdm_iface_set_sysclk()
107 if (!iface->mclk) { in axg_tdm_iface_set_sysclk()
108 dev_warn(dai->dev, "master clock not provided\n"); in axg_tdm_iface_set_sysclk()
110 ret = clk_set_rate(iface->mclk, freq); in axg_tdm_iface_set_sysclk()
112 iface->mclk_rate = freq; in axg_tdm_iface_set_sysclk()
119 static int axg_tdm_iface_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) in axg_tdm_iface_set_fmt() argument
121 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); in axg_tdm_iface_set_fmt()
125 if (!iface->mclk) { in axg_tdm_iface_set_fmt()
126 dev_err(dai->dev, "cpu clock master: mclk missing\n"); in axg_tdm_iface_set_fmt()
127 return -ENODEV; in axg_tdm_iface_set_fmt()
136 dev_err(dai->dev, "only BP_FP and BC_FC are supported\n"); in axg_tdm_iface_set_fmt()
139 return -EINVAL; in axg_tdm_iface_set_fmt()
142 iface->fmt = fmt; in axg_tdm_iface_set_fmt()
147 struct snd_soc_dai *dai) in axg_tdm_iface_startup() argument
149 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); in axg_tdm_iface_startup()
151 snd_soc_dai_get_dma_data(dai, substream); in axg_tdm_iface_startup()
154 if (!axg_tdm_slots_total(ts->mask)) { in axg_tdm_iface_startup()
155 dev_err(dai->dev, "interface has not slots\n"); in axg_tdm_iface_startup()
156 return -EINVAL; in axg_tdm_iface_startup()
159 if (snd_soc_component_active(dai->component)) { in axg_tdm_iface_startup()
161 ret = snd_pcm_hw_constraint_single(substream->runtime, in axg_tdm_iface_startup()
163 iface->rate); in axg_tdm_iface_startup()
166 /* Limit rate according to the slot number and width */ in axg_tdm_iface_startup()
168 MAX_SCLK / (iface->slots * iface->slot_width); in axg_tdm_iface_startup()
169 ret = snd_pcm_hw_constraint_minmax(substream->runtime, in axg_tdm_iface_startup()
175 dev_err(dai->dev, "can't set iface rate constraint\n"); in axg_tdm_iface_startup()
184 struct snd_soc_dai *dai) in axg_tdm_iface_set_stream() argument
186 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); in axg_tdm_iface_set_stream()
187 struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream); in axg_tdm_iface_set_stream()
192 iface->rate = params_rate(params); in axg_tdm_iface_set_stream()
195 if (axg_tdm_slots_total(ts->mask) < channels) { in axg_tdm_iface_set_stream()
196 dev_err(dai->dev, "not enough slots for channels\n"); in axg_tdm_iface_set_stream()
197 return -EINVAL; in axg_tdm_iface_set_stream()
200 if (iface->slot_width < width) { in axg_tdm_iface_set_stream()
201 dev_err(dai->dev, "incompatible slots width for stream\n"); in axg_tdm_iface_set_stream()
202 return -EINVAL; in axg_tdm_iface_set_stream()
206 ts->physical_width = params_physical_width(params); in axg_tdm_iface_set_stream()
207 ts->width = params_width(params); in axg_tdm_iface_set_stream()
208 ts->channels = params_channels(params); in axg_tdm_iface_set_stream()
213 static int axg_tdm_iface_set_lrclk(struct snd_soc_dai *dai, in axg_tdm_iface_set_lrclk() argument
216 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); in axg_tdm_iface_set_lrclk()
220 ret = clk_set_rate(iface->lrclk, params_rate(params)); in axg_tdm_iface_set_lrclk()
222 dev_err(dai->dev, "setting sample clock failed: %d\n", ret); in axg_tdm_iface_set_lrclk()
226 switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { in axg_tdm_iface_set_lrclk()
246 return -EINVAL; in axg_tdm_iface_set_lrclk()
249 ret = clk_set_duty_cycle(iface->lrclk, ratio_num, 2); in axg_tdm_iface_set_lrclk()
251 dev_err(dai->dev, in axg_tdm_iface_set_lrclk()
257 ret = clk_set_phase(iface->lrclk, in axg_tdm_iface_set_lrclk()
258 axg_tdm_lrclk_invert(iface->fmt) ? 180 : 0); in axg_tdm_iface_set_lrclk()
260 dev_err(dai->dev, in axg_tdm_iface_set_lrclk()
268 static int axg_tdm_iface_set_sclk(struct snd_soc_dai *dai, in axg_tdm_iface_set_sclk() argument
271 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); in axg_tdm_iface_set_sclk()
275 srate = iface->slots * iface->slot_width * params_rate(params); in axg_tdm_iface_set_sclk()
277 if (!iface->mclk_rate) { in axg_tdm_iface_set_sclk()
279 clk_set_rate(iface->mclk, 2 * srate); in axg_tdm_iface_set_sclk()
282 if (iface->mclk_rate % srate) { in axg_tdm_iface_set_sclk()
283 dev_err(dai->dev, in axg_tdm_iface_set_sclk()
285 srate, iface->mclk_rate); in axg_tdm_iface_set_sclk()
286 return -EINVAL; in axg_tdm_iface_set_sclk()
290 ret = clk_set_rate(iface->sclk, srate); in axg_tdm_iface_set_sclk()
292 dev_err(dai->dev, "setting bit clock failed: %d\n", ret); in axg_tdm_iface_set_sclk()
297 ret = clk_set_phase(iface->sclk, in axg_tdm_iface_set_sclk()
298 axg_tdm_sclk_invert(iface->fmt) ? 0 : 180); in axg_tdm_iface_set_sclk()
300 dev_err(dai->dev, "setting bit clock phase failed: %d\n", ret); in axg_tdm_iface_set_sclk()
309 struct snd_soc_dai *dai) in axg_tdm_iface_hw_params() argument
311 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); in axg_tdm_iface_hw_params()
312 struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream); in axg_tdm_iface_hw_params()
315 switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) { in axg_tdm_iface_hw_params()
319 if (iface->slots > 2) { in axg_tdm_iface_hw_params()
320 dev_err(dai->dev, "bad slot number for format: %d\n", in axg_tdm_iface_hw_params()
321 iface->slots); in axg_tdm_iface_hw_params()
322 return -EINVAL; in axg_tdm_iface_hw_params()
331 dev_err(dai->dev, "unsupported dai format\n"); in axg_tdm_iface_hw_params()
332 return -EINVAL; in axg_tdm_iface_hw_params()
335 ret = axg_tdm_iface_set_stream(substream, params, dai); in axg_tdm_iface_hw_params()
339 if ((iface->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == in axg_tdm_iface_hw_params()
341 ret = axg_tdm_iface_set_sclk(dai, params); in axg_tdm_iface_hw_params()
345 ret = axg_tdm_iface_set_lrclk(dai, params); in axg_tdm_iface_hw_params()
350 ret = axg_tdm_stream_set_cont_clocks(ts, iface->fmt); in axg_tdm_iface_hw_params()
352 dev_err(dai->dev, "failed to apply continuous clock setting\n"); in axg_tdm_iface_hw_params()
358 struct snd_soc_dai *dai) in axg_tdm_iface_hw_free() argument
360 struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream); in axg_tdm_iface_hw_free()
367 struct snd_soc_dai *dai) in axg_tdm_iface_trigger() argument
370 snd_soc_dai_get_dma_data(dai, substream); in axg_tdm_iface_trigger()
384 return -EINVAL; in axg_tdm_iface_trigger()
390 static int axg_tdm_iface_remove_dai(struct snd_soc_dai *dai) in axg_tdm_iface_remove_dai() argument
395 struct axg_tdm_stream *ts = snd_soc_dai_dma_data_get(dai, stream); in axg_tdm_iface_remove_dai()
404 static int axg_tdm_iface_probe_dai(struct snd_soc_dai *dai) in axg_tdm_iface_probe_dai() argument
406 struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai); in axg_tdm_iface_probe_dai()
412 if (!snd_soc_dai_get_widget(dai, stream)) in axg_tdm_iface_probe_dai()
417 axg_tdm_iface_remove_dai(dai); in axg_tdm_iface_probe_dai()
418 return -ENOMEM; in axg_tdm_iface_probe_dai()
420 snd_soc_dai_dma_data_set(dai, stream, ts); in axg_tdm_iface_probe_dai()
437 /* TDM Backend DAIs */
440 .name = "TDM Pad",
459 .name = "TDM Loopback",
483 ret = clk_prepare_enable(iface->mclk); in axg_tdm_iface_set_bias_level()
488 clk_disable_unprepare(iface->mclk); in axg_tdm_iface_set_bias_level()
516 { .compatible = "amlogic,axg-tdm-iface", },
523 struct device *dev = &pdev->dev; in axg_tdm_iface_probe()
530 return -ENOMEM; in axg_tdm_iface_probe()
534 * Duplicate dai driver: depending on the slot masks configuration in axg_tdm_iface_probe()
535 * We'll change the number of channel provided by DAI stream, so dpcm in axg_tdm_iface_probe()
541 return -ENOMEM; in axg_tdm_iface_probe()
548 iface->sclk = devm_clk_get(dev, "sclk"); in axg_tdm_iface_probe()
549 if (IS_ERR(iface->sclk)) in axg_tdm_iface_probe()
550 return dev_err_probe(dev, PTR_ERR(iface->sclk), "failed to get sclk\n"); in axg_tdm_iface_probe()
553 iface->lrclk = devm_clk_get(dev, "lrclk"); in axg_tdm_iface_probe()
554 if (IS_ERR(iface->lrclk)) in axg_tdm_iface_probe()
555 return dev_err_probe(dev, PTR_ERR(iface->lrclk), "failed to get lrclk\n"); in axg_tdm_iface_probe()
558 * mclk maybe be missing when the cpu dai is in slave mode and in axg_tdm_iface_probe()
561 * throw an error if the cpu dai is master and mclk is missing in axg_tdm_iface_probe()
563 iface->mclk = devm_clk_get_optional(dev, "mclk"); in axg_tdm_iface_probe()
564 if (IS_ERR(iface->mclk)) in axg_tdm_iface_probe()
565 return dev_err_probe(dev, PTR_ERR(iface->mclk), "failed to get mclk\n"); in axg_tdm_iface_probe()
575 .name = "axg-tdm-iface",
581 MODULE_DESCRIPTION("Amlogic AXG TDM interface driver");