Unverified Commit 13c1629d authored by Codrin Ciubotariu's avatar Codrin Ciubotariu Committed by Mark Brown
Browse files

ASoC: mchp-i2s-mcc: Add multi-channel support for I2S and LEFT_J formats



The latest I2S-MCC available in SAMA7G5 supports multi-channel for I2S and
Left-Justified formats. For this, the new version uses 8 (4 * 2) input and
output pins, with each pin being responsible for 2 channels. This sums up
to a total of 8 channels for synchronous capture and playback.

Signed-off-by: default avatarCodrin Ciubotariu <codrin.ciubotariu@microchip.com>
Link: https://lore.kernel.org/r/20210301170905.835091-4-codrin.ciubotariu@microchip.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 99ac2f8d
Loading
Loading
Loading
Loading
+38 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@
#include <linux/clk.h>
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/mfd/syscon.h>
#include <linux/lcm.h>
#include <linux/lcm.h>
#include <linux/of_device.h>


#include <sound/core.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm.h>
@@ -225,6 +226,10 @@ static const struct regmap_config mchp_i2s_mcc_regmap_config = {
	.max_register = MCHP_I2SMCC_VERSION,
	.max_register = MCHP_I2SMCC_VERSION,
};
};


struct mchp_i2s_mcc_soc_data {
	unsigned int	data_pin_pair_num;
};

struct mchp_i2s_mcc_dev {
struct mchp_i2s_mcc_dev {
	struct wait_queue_head			wq_txrdy;
	struct wait_queue_head			wq_txrdy;
	struct wait_queue_head			wq_rxrdy;
	struct wait_queue_head			wq_rxrdy;
@@ -232,6 +237,7 @@ struct mchp_i2s_mcc_dev {
	struct regmap				*regmap;
	struct regmap				*regmap;
	struct clk				*pclk;
	struct clk				*pclk;
	struct clk				*gclk;
	struct clk				*gclk;
	const struct mchp_i2s_mcc_soc_data	*soc;
	struct snd_dmaengine_dai_dma_data	playback;
	struct snd_dmaengine_dai_dma_data	playback;
	struct snd_dmaengine_dai_dma_data	capture;
	struct snd_dmaengine_dai_dma_data	capture;
	unsigned int				fmt;
	unsigned int				fmt;
@@ -549,6 +555,17 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
	}
	}


	if (dev->fmt & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
	if (dev->fmt & (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_LEFT_J)) {
		/* for I2S and LEFT_J one pin is needed for every 2 channels */
		if (channels > dev->soc->data_pin_pair_num * 2) {
			dev_err(dev->dev,
				"unsupported number of audio channels: %d\n",
				channels);
			return -EINVAL;
		}

		/* enable for interleaved format */
		mrb |= MCHP_I2SMCC_MRB_CRAMODE_REGULAR;

		switch (channels) {
		switch (channels) {
		case 1:
		case 1:
			if (is_playback)
			if (is_playback)
@@ -558,6 +575,12 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
			break;
			break;
		case 2:
		case 2:
			break;
			break;
		case 4:
			mra |= MCHP_I2SMCC_MRA_WIRECFG_I2S_2_TDM_1;
			break;
		case 8:
			mra |= MCHP_I2SMCC_MRA_WIRECFG_I2S_4_TDM_2;
			break;
		default:
		default:
			dev_err(dev->dev, "unsupported number of audio channels\n");
			dev_err(dev->dev, "unsupported number of audio channels\n");
			return -EINVAL;
			return -EINVAL;
@@ -869,12 +892,22 @@ static const struct snd_soc_component_driver mchp_i2s_mcc_component = {
};
};


#ifdef CONFIG_OF
#ifdef CONFIG_OF
static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sam9x60 = {
	.data_pin_pair_num = 1,
};

static struct mchp_i2s_mcc_soc_data mchp_i2s_mcc_sama7g5 = {
	.data_pin_pair_num = 4,
};

static const struct of_device_id mchp_i2s_mcc_dt_ids[] = {
static const struct of_device_id mchp_i2s_mcc_dt_ids[] = {
	{
	{
		.compatible = "microchip,sam9x60-i2smcc",
		.compatible = "microchip,sam9x60-i2smcc",
		.data = &mchp_i2s_mcc_sam9x60,
	},
	},
	{
	{
		.compatible = "microchip,sama7g5-i2smcc",
		.compatible = "microchip,sama7g5-i2smcc",
		.data = &mchp_i2s_mcc_sama7g5,
	},
	},
	{ /* sentinel */ }
	{ /* sentinel */ }
};
};
@@ -932,6 +965,11 @@ static int mchp_i2s_mcc_probe(struct platform_device *pdev)
		dev->gclk = NULL;
		dev->gclk = NULL;
	}
	}


	dev->soc = of_device_get_match_data(&pdev->dev);
	if (!dev->soc) {
		dev_err(&pdev->dev, "failed to get soc data\n");
		return -ENODEV;
	}
	dev->dev = &pdev->dev;
	dev->dev = &pdev->dev;
	dev->regmap = regmap;
	dev->regmap = regmap;
	platform_set_drvdata(pdev, dev);
	platform_set_drvdata(pdev, dev);