Unverified Commit a5a89037 authored by Jerome Brunet's avatar Jerome Brunet Committed by Mark Brown
Browse files

ASoC: meson: axg-tdm: add continuous clock support



Some devices may need the clocks running, even while paused.
Add support for this use case.

Signed-off-by: default avatarJerome Brunet <jbrunet@baylibre.com>
Link: https://lore.kernel.org/r/20240426152946.3078805-5-jbrunet@baylibre.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent f949ed45
Loading
Loading
Loading
Loading
+40 −0
Original line number Diff line number Diff line
@@ -392,6 +392,46 @@ void axg_tdm_stream_free(struct axg_tdm_stream *ts)
}
EXPORT_SYMBOL_GPL(axg_tdm_stream_free);

int axg_tdm_stream_set_cont_clocks(struct axg_tdm_stream *ts,
				   unsigned int fmt)
{
	int ret = 0;

	if (fmt & SND_SOC_DAIFMT_CONT) {
		/* Clock are already enabled - skipping */
		if (ts->clk_enabled)
			return 0;

		ret = clk_prepare_enable(ts->iface->mclk);
		if (ret)
			return ret;

		ret = clk_prepare_enable(ts->iface->sclk);
		if (ret)
			goto err_sclk;

		ret = clk_prepare_enable(ts->iface->lrclk);
		if (ret)
			goto err_lrclk;

		ts->clk_enabled = true;
		return 0;
	}

	/* Clocks are already disabled - skipping */
	if (!ts->clk_enabled)
		return 0;

	clk_disable_unprepare(ts->iface->lrclk);
err_lrclk:
	clk_disable_unprepare(ts->iface->sclk);
err_sclk:
	clk_disable_unprepare(ts->iface->mclk);
	ts->clk_enabled = false;
	return ret;
}
EXPORT_SYMBOL_GPL(axg_tdm_stream_set_cont_clocks);

MODULE_DESCRIPTION("Amlogic AXG TDM formatter driver");
MODULE_AUTHOR("Jerome Brunet <jbrunet@baylibre.com>");
MODULE_LICENSE("GPL v2");
+15 −1
Original line number Diff line number Diff line
@@ -309,6 +309,7 @@ static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream,
				   struct snd_soc_dai *dai)
{
	struct axg_tdm_iface *iface = snd_soc_dai_get_drvdata(dai);
	struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);
	int ret;

	switch (iface->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
@@ -346,7 +347,19 @@ static int axg_tdm_iface_hw_params(struct snd_pcm_substream *substream,
			return ret;
	}

	return 0;
	ret = axg_tdm_stream_set_cont_clocks(ts, iface->fmt);
	if (ret)
		dev_err(dai->dev, "failed to apply continuous clock setting\n");

	return ret;
}

static int axg_tdm_iface_hw_free(struct snd_pcm_substream *substream,
				 struct snd_soc_dai *dai)
{
	struct axg_tdm_stream *ts = snd_soc_dai_get_dma_data(dai, substream);

	return axg_tdm_stream_set_cont_clocks(ts, 0);
}

static int axg_tdm_iface_trigger(struct snd_pcm_substream *substream,
@@ -417,6 +430,7 @@ static const struct snd_soc_dai_ops axg_tdm_iface_ops = {
	.set_fmt	= axg_tdm_iface_set_fmt,
	.startup	= axg_tdm_iface_startup,
	.hw_params	= axg_tdm_iface_hw_params,
	.hw_free	= axg_tdm_iface_hw_free,
	.trigger	= axg_tdm_iface_trigger,
};

+5 −0
Original line number Diff line number Diff line
@@ -58,12 +58,17 @@ struct axg_tdm_stream {
	unsigned int physical_width;
	u32 *mask;
	bool ready;

	/* For continuous clock tracking */
	bool clk_enabled;
};

struct axg_tdm_stream *axg_tdm_stream_alloc(struct axg_tdm_iface *iface);
void axg_tdm_stream_free(struct axg_tdm_stream *ts);
int axg_tdm_stream_start(struct axg_tdm_stream *ts);
void axg_tdm_stream_stop(struct axg_tdm_stream *ts);
int axg_tdm_stream_set_cont_clocks(struct axg_tdm_stream *ts,
				   unsigned int fmt);

static inline int axg_tdm_stream_reset(struct axg_tdm_stream *ts)
{