summaryrefslogtreecommitdiff
path: root/sound/soc/atmel/mchp-i2s-mcc.c
diff options
context:
space:
mode:
Diffstat (limited to 'sound/soc/atmel/mchp-i2s-mcc.c')
-rw-r--r--sound/soc/atmel/mchp-i2s-mcc.c85
1 files changed, 56 insertions, 29 deletions
diff --git a/sound/soc/atmel/mchp-i2s-mcc.c b/sound/soc/atmel/mchp-i2s-mcc.c
index 6d1227a1d67b..17d138bb9064 100644
--- a/sound/soc/atmel/mchp-i2s-mcc.c
+++ b/sound/soc/atmel/mchp-i2s-mcc.c
@@ -16,7 +16,7 @@
#include <linux/clk.h>
#include <linux/mfd/syscon.h>
#include <linux/lcm.h>
-#include <linux/of_device.h>
+#include <linux/of.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -221,6 +221,15 @@
#define MCHP_I2SMCC_MAX_CHANNELS 8
#define MCHP_I2MCC_TDM_SLOT_WIDTH 32
+/*
+ * ---- DMA chunk size allowed ----
+ */
+#define MCHP_I2SMCC_DMA_8_WORD_CHUNK 8
+#define MCHP_I2SMCC_DMA_4_WORD_CHUNK 4
+#define MCHP_I2SMCC_DMA_2_WORD_CHUNK 2
+#define MCHP_I2SMCC_DMA_1_WORD_CHUNK 1
+#define DMA_BURST_ALIGNED(_p, _s, _w) !(_p % (_s * _w))
+
static const struct regmap_config mchp_i2s_mcc_regmap_config = {
.reg_bits = 32,
.reg_stride = 4,
@@ -350,7 +359,7 @@ static int mchp_i2s_mcc_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
return -EINVAL;
/* We can't generate only FSYNC */
- if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_CBP_CFC)
+ if ((fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == SND_SOC_DAIFMT_BC_FP)
return -EINVAL;
/* We can only reconfigure the IP when it's stopped */
@@ -504,12 +513,30 @@ static int mchp_i2s_mcc_is_running(struct mchp_i2s_mcc_dev *dev)
return !!(sr & (MCHP_I2SMCC_SR_TXEN | MCHP_I2SMCC_SR_RXEN));
}
+static inline int mchp_i2s_mcc_period_to_maxburst(int period_size, int sample_size)
+{
+ int p_size = period_size;
+ int s_size = sample_size;
+
+ if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_I2SMCC_DMA_8_WORD_CHUNK))
+ return MCHP_I2SMCC_DMA_8_WORD_CHUNK;
+ if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_I2SMCC_DMA_4_WORD_CHUNK))
+ return MCHP_I2SMCC_DMA_4_WORD_CHUNK;
+ if (DMA_BURST_ALIGNED(p_size, s_size, MCHP_I2SMCC_DMA_2_WORD_CHUNK))
+ return MCHP_I2SMCC_DMA_2_WORD_CHUNK;
+ return MCHP_I2SMCC_DMA_1_WORD_CHUNK;
+}
+
static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
{
unsigned long rate = 0;
struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
+ int sample_bytes = params_physical_width(params) / 8;
+ int period_bytes = params_period_size(params) *
+ params_channels(params) * sample_bytes;
+ int maxburst;
u32 mra = 0;
u32 mrb = 0;
unsigned int channels = params_channels(params);
@@ -519,9 +546,9 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
int ret;
bool is_playback = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK);
- dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u\n",
+ dev_dbg(dev->dev, "%s() rate=%u format=%#x width=%u channels=%u period_bytes=%d\n",
__func__, params_rate(params), params_format(params),
- params_width(params), params_channels(params));
+ params_width(params), params_channels(params), period_bytes);
switch (dev->fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_I2S:
@@ -547,19 +574,19 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
}
switch (dev->fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) {
- case SND_SOC_DAIFMT_CBC_CFC:
+ case SND_SOC_DAIFMT_BP_FP:
/* cpu is BCLK and LRC master */
mra |= MCHP_I2SMCC_MRA_MODE_MASTER;
if (dev->sysclk)
mra |= MCHP_I2SMCC_MRA_IMCKMODE_GEN;
set_divs = 1;
break;
- case SND_SOC_DAIFMT_CBC_CFP:
+ case SND_SOC_DAIFMT_BP_FC:
/* cpu is BCLK master */
mrb |= MCHP_I2SMCC_MRB_CLKSEL_INT;
set_divs = 1;
fallthrough;
- case SND_SOC_DAIFMT_CBP_CFP:
+ case SND_SOC_DAIFMT_BC_FC:
/* cpu is slave */
mra |= MCHP_I2SMCC_MRA_MODE_SLAVE;
if (dev->sysclk)
@@ -630,11 +657,12 @@ static int mchp_i2s_mcc_hw_params(struct snd_pcm_substream *substream,
* We must have the same burst size configured
* in the DMA transfer and in out IP
*/
- mrb |= MCHP_I2SMCC_MRB_DMACHUNK(channels);
+ maxburst = mchp_i2s_mcc_period_to_maxburst(period_bytes, sample_bytes);
+ mrb |= MCHP_I2SMCC_MRB_DMACHUNK(maxburst);
if (is_playback)
- dev->playback.maxburst = 1 << (fls(channels) - 1);
+ dev->playback.maxburst = maxburst;
else
- dev->capture.maxburst = 1 << (fls(channels) - 1);
+ dev->capture.maxburst = maxburst;
switch (params_format(params)) {
case SNDRV_PCM_FORMAT_S8:
@@ -870,17 +898,6 @@ static int mchp_i2s_mcc_startup(struct snd_pcm_substream *substream,
return 0;
}
-static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
- .set_sysclk = mchp_i2s_mcc_set_sysclk,
- .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio,
- .startup = mchp_i2s_mcc_startup,
- .trigger = mchp_i2s_mcc_trigger,
- .hw_params = mchp_i2s_mcc_hw_params,
- .hw_free = mchp_i2s_mcc_hw_free,
- .set_fmt = mchp_i2s_mcc_set_dai_fmt,
- .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot,
-};
-
static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
{
struct mchp_i2s_mcc_dev *dev = snd_soc_dai_get_drvdata(dai);
@@ -895,6 +912,18 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
return 0;
}
+static const struct snd_soc_dai_ops mchp_i2s_mcc_dai_ops = {
+ .probe = mchp_i2s_mcc_dai_probe,
+ .set_sysclk = mchp_i2s_mcc_set_sysclk,
+ .set_bclk_ratio = mchp_i2s_mcc_set_bclk_ratio,
+ .startup = mchp_i2s_mcc_startup,
+ .trigger = mchp_i2s_mcc_trigger,
+ .hw_params = mchp_i2s_mcc_hw_params,
+ .hw_free = mchp_i2s_mcc_hw_free,
+ .set_fmt = mchp_i2s_mcc_set_dai_fmt,
+ .set_tdm_slot = mchp_i2s_mcc_set_dai_tdm_slot,
+};
+
#define MCHP_I2SMCC_RATES SNDRV_PCM_RATE_8000_192000
#define MCHP_I2SMCC_FORMATS (SNDRV_PCM_FMTBIT_S8 | \
@@ -906,16 +935,15 @@ static int mchp_i2s_mcc_dai_probe(struct snd_soc_dai *dai)
SNDRV_PCM_FMTBIT_S32_LE)
static struct snd_soc_dai_driver mchp_i2s_mcc_dai = {
- .probe = mchp_i2s_mcc_dai_probe,
.playback = {
- .stream_name = "I2SMCC-Playback",
+ .stream_name = "Playback",
.channels_min = 1,
.channels_max = 8,
.rates = MCHP_I2SMCC_RATES,
.formats = MCHP_I2SMCC_FORMATS,
},
.capture = {
- .stream_name = "I2SMCC-Capture",
+ .stream_name = "Capture",
.channels_min = 1,
.channels_max = 8,
.rates = MCHP_I2SMCC_RATES,
@@ -928,7 +956,8 @@ static struct snd_soc_dai_driver mchp_i2s_mcc_dai = {
};
static const struct snd_soc_component_driver mchp_i2s_mcc_component = {
- .name = "mchp-i2s-mcc",
+ .name = "mchp-i2s-mcc",
+ .legacy_dai_naming = 1,
};
#ifdef CONFIG_OF
@@ -1087,19 +1116,17 @@ static int mchp_i2s_mcc_probe(struct platform_device *pdev)
return 0;
}
-static int mchp_i2s_mcc_remove(struct platform_device *pdev)
+static void mchp_i2s_mcc_remove(struct platform_device *pdev)
{
struct mchp_i2s_mcc_dev *dev = platform_get_drvdata(pdev);
clk_disable_unprepare(dev->pclk);
-
- return 0;
}
static struct platform_driver mchp_i2s_mcc_driver = {
.driver = {
.name = "mchp_i2s_mcc",
- .of_match_table = of_match_ptr(mchp_i2s_mcc_dt_ids),
+ .of_match_table = mchp_i2s_mcc_dt_ids,
},
.probe = mchp_i2s_mcc_probe,
.remove = mchp_i2s_mcc_remove,