Unverified Commit 7bf7d055 authored by Luca Ceresoli's avatar Luca Ceresoli Committed by Mark Brown
Browse files

ASoC: axi-i2s: let both capture and playback be optional



Both the capture and playback channels are optional in the axi_i2s IP
block. Reflect this in the driver by enabling only the channel(s) that
have a DMA.

Signed-off-by: default avatarLuca Ceresoli <luca@lucaceresoli.net>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 7d7b25d0
Loading
Loading
Loading
Loading
+48 −20
Original line number Diff line number Diff line
@@ -43,6 +43,9 @@ struct axi_i2s {
	struct clk *clk;
	struct clk *clk_ref;

	bool   has_capture;
	bool   has_playback;

	struct snd_soc_dai_driver dai_driver;

	struct snd_dmaengine_dai_dma_data capture_dma_data;
@@ -136,8 +139,10 @@ static int axi_i2s_dai_probe(struct snd_soc_dai *dai)
{
	struct axi_i2s *i2s = snd_soc_dai_get_drvdata(dai);

	snd_soc_dai_init_dma_data(dai, &i2s->playback_dma_data,
		&i2s->capture_dma_data);
	snd_soc_dai_init_dma_data(
		dai,
		i2s->has_playback ? &i2s->playback_dma_data : NULL,
		i2s->has_capture  ? &i2s->capture_dma_data  : NULL);

	return 0;
}
@@ -151,18 +156,6 @@ static const struct snd_soc_dai_ops axi_i2s_dai_ops = {

static struct snd_soc_dai_driver axi_i2s_dai = {
	.probe = axi_i2s_dai_probe,
	.playback = {
		.channels_min = 2,
		.channels_max = 2,
		.rates = SNDRV_PCM_RATE_KNOT,
		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE,
	},
	.capture = {
		.channels_min = 2,
		.channels_max = 2,
		.rates = SNDRV_PCM_RATE_KNOT,
		.formats = SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE,
	},
	.ops = &axi_i2s_dai_ops,
	.symmetric_rates = 1,
};
@@ -178,6 +171,19 @@ static const struct regmap_config axi_i2s_regmap_config = {
	.max_register = AXI_I2S_REG_STATUS,
};

static void axi_i2s_parse_of(struct axi_i2s *i2s, const struct device_node *np)
{
	struct property *dma_names;
	const char *dma_name;

	of_property_for_each_string(np, "dma-names", dma_names, dma_name) {
		if (strcmp(dma_name, "rx") == 0)
			i2s->has_capture = true;
		if (strcmp(dma_name, "tx") == 0)
			i2s->has_playback = true;
	}
}

static int axi_i2s_probe(struct platform_device *pdev)
{
	struct resource *res;
@@ -191,6 +197,8 @@ static int axi_i2s_probe(struct platform_device *pdev)

	platform_set_drvdata(pdev, i2s);

	axi_i2s_parse_of(i2s, pdev->dev.of_node);

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	base = devm_ioremap_resource(&pdev->dev, res);
	if (IS_ERR(base))
@@ -213,13 +221,29 @@ static int axi_i2s_probe(struct platform_device *pdev)
	if (ret)
		return ret;

	if (i2s->has_playback) {
		axi_i2s_dai.playback.channels_min = 2;
		axi_i2s_dai.playback.channels_max = 2;
		axi_i2s_dai.playback.rates = SNDRV_PCM_RATE_KNOT;
		axi_i2s_dai.playback.formats =
			SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE;

		i2s->playback_dma_data.addr = res->start + AXI_I2S_REG_TX_FIFO;
		i2s->playback_dma_data.addr_width = 4;
		i2s->playback_dma_data.maxburst = 1;
	}

	if (i2s->has_capture) {
		axi_i2s_dai.capture.channels_min = 2;
		axi_i2s_dai.capture.channels_max = 2;
		axi_i2s_dai.capture.rates = SNDRV_PCM_RATE_KNOT;
		axi_i2s_dai.capture.formats =
			SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_U32_LE;

		i2s->capture_dma_data.addr = res->start + AXI_I2S_REG_RX_FIFO;
		i2s->capture_dma_data.addr_width = 4;
		i2s->capture_dma_data.maxburst = 1;
	}

	i2s->ratnum.num = clk_get_rate(i2s->clk_ref) / 2 / AXI_I2S_BITS_PER_FRAME;
	i2s->ratnum.den_step = 1;
@@ -240,6 +264,10 @@ static int axi_i2s_probe(struct platform_device *pdev)
	if (ret)
		goto err_clk_disable;

	dev_info(&pdev->dev, "probed, capture %s, playback %s\n",
		 i2s->has_capture ? "enabled" : "disabled",
		 i2s->has_playback ? "enabled" : "disabled");

	return 0;

err_clk_disable: