[PATCH 0/7] ASoC: fsl_sai: Cleanups and 1:1 bclk:mclk ratio support
This series has some updates for the fsl_sai driver: Some general cleanup patches, a bugfix in the ip revision checking and finally the mclk setting is made more accurate and support for 1:1 bclk:mclk setting is added.
Ahmad Fatoum (2): ASoC: fsl_sai: simplify register poking in fsl_sai_set_bclk ASoC: fsl_sai: implement 1:1 bclk:mclk ratio support
Sascha Hauer (5): ASoC: fsl_sai: Drop unnecessary defines ASoC: fsl_sai: simplify irq return value ASoC: fsl_sai: store full version instead of major/minor ASoC: fsl_sai: Use better variable names ASoC: fsl_sai: use DIV_ROUND_CLOSEST() to calculate divider
sound/soc/fsl/fsl_sai.c | 100 ++++++++++++++++++++-------------------- sound/soc/fsl/fsl_sai.h | 9 +--- 2 files changed, 52 insertions(+), 57 deletions(-)
The fsl_sai driver has FSL_FMT_TRANSMITTER and FSL_FMT_RECEIVER defines which are used in a single function only then are then only translated into a bool 'tx' variable. Drop the defines and pass the boolean value directly to fsl_sai_set_dai_sysclk_tr(). No functional change.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- sound/soc/fsl/fsl_sai.c | 16 ++++++---------- sound/soc/fsl/fsl_sai.h | 3 --- 2 files changed, 6 insertions(+), 13 deletions(-)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 10544fa27dc0b..d79cb7eb3b262 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -167,11 +167,10 @@ static int fsl_sai_set_dai_bclk_ratio(struct snd_soc_dai *dai, }
static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, - int clk_id, unsigned int freq, int fsl_dir) + int clk_id, unsigned int freq, bool tx) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); unsigned int ofs = sai->soc_data->reg_offset; - bool tx = fsl_dir == FSL_FMT_TRANSMITTER; u32 val_cr2 = 0;
switch (clk_id) { @@ -205,15 +204,13 @@ static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, if (dir == SND_SOC_CLOCK_IN) return 0;
- ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, - FSL_FMT_TRANSMITTER); + ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, true); if (ret) { dev_err(cpu_dai->dev, "Cannot set tx sysclk: %d\n", ret); return ret; }
- ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, - FSL_FMT_RECEIVER); + ret = fsl_sai_set_dai_sysclk_tr(cpu_dai, clk_id, freq, false); if (ret) dev_err(cpu_dai->dev, "Cannot set rx sysclk: %d\n", ret);
@@ -221,11 +218,10 @@ static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, }
static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, - unsigned int fmt, int fsl_dir) + unsigned int fmt, bool tx) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); unsigned int ofs = sai->soc_data->reg_offset; - bool tx = fsl_dir == FSL_FMT_TRANSMITTER; u32 val_cr2 = 0, val_cr4 = 0;
if (!sai->is_lsb_first) @@ -332,13 +328,13 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) { int ret;
- ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_TRANSMITTER); + ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, true); if (ret) { dev_err(cpu_dai->dev, "Cannot set tx format: %d\n", ret); return ret; }
- ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, FSL_FMT_RECEIVER); + ret = fsl_sai_set_dai_fmt_tr(cpu_dai, fmt, false); if (ret) dev_err(cpu_dai->dev, "Cannot set rx format: %d\n", ret);
diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 9aaf231bc0244..4e76ae43d1968 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -201,9 +201,6 @@ #define FSL_SAI_REC_SYN BIT(4) #define FSL_SAI_USE_I2S_SLAVE BIT(5)
-#define FSL_FMT_TRANSMITTER 0 -#define FSL_FMT_RECEIVER 1 - /* SAI clock sources */ #define FSL_SAI_CLK_BUS 0 #define FSL_SAI_CLK_MAST1 1
Instead of using a boolean "irq_none" to describe the interrupt handlers return value use a variable of type irqreturn_t and return it directly. No functional change.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- sound/soc/fsl/fsl_sai.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index d79cb7eb3b262..56311a0f23b95 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -62,7 +62,7 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) unsigned int ofs = sai->soc_data->reg_offset; struct device *dev = &sai->pdev->dev; u32 flags, xcsr, mask; - bool irq_none = true; + irqreturn_t iret = IRQ_NONE;
/* * Both IRQ status bits and IRQ mask bits are in the xCSR but @@ -76,7 +76,7 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) flags = xcsr & mask;
if (flags) - irq_none = false; + iret = IRQ_HANDLED; else goto irq_rx;
@@ -110,7 +110,7 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) flags = xcsr & mask;
if (flags) - irq_none = false; + iret = IRQ_HANDLED; else goto out;
@@ -139,10 +139,7 @@ static irqreturn_t fsl_sai_isr(int irq, void *devid) regmap_write(sai->regmap, FSL_SAI_RCSR(ofs), flags | xcsr);
out: - if (irq_none) - return IRQ_NONE; - else - return IRQ_HANDLED; + return iret; }
static int fsl_sai_set_dai_tdm_slot(struct snd_soc_dai *cpu_dai, u32 tx_mask,
From: Ahmad Fatoum a.fatoum@pengutronix.de
Depending on SAI synchronization mode, the same value is either written to FSL_SAI_TCR2 or FSL_SAI_RCR2 or nothing is written at all.
As the computation is the same either way, factor it out to make it clearer what the difference is. No functional change.
Signed-off-by: Ahmad Fatoum a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- sound/soc/fsl/fsl_sai.c | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 56311a0f23b95..5f627ccd172b2 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -341,7 +341,7 @@ static int fsl_sai_set_dai_fmt(struct snd_soc_dai *cpu_dai, unsigned int fmt) static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) { struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); - unsigned int ofs = sai->soc_data->reg_offset; + unsigned int reg, ofs = sai->soc_data->reg_offset; unsigned long clk_rate; u32 savediv = 0, ratio, savesub = freq; int adir = tx ? RX : TX; @@ -401,6 +401,9 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) return -EINVAL; }
+ dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n", + sai->mclk_id[tx], savediv, savesub); + /* * 1) For Asynchronous mode, we must set RCR2 register for capture, and * set TCR2 register for playback. @@ -411,22 +414,16 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) * 4) For Tx and Rx are both Synchronous with another SAI, we just * ignore it. */ - if (fsl_sai_dir_is_synced(sai, adir)) { - regmap_update_bits(sai->regmap, FSL_SAI_xCR2(!tx, ofs), - FSL_SAI_CR2_MSEL_MASK, - FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); - regmap_update_bits(sai->regmap, FSL_SAI_xCR2(!tx, ofs), - FSL_SAI_CR2_DIV_MASK, savediv - 1); - } else if (!sai->synchronous[dir]) { - regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), - FSL_SAI_CR2_MSEL_MASK, - FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); - regmap_update_bits(sai->regmap, FSL_SAI_xCR2(tx, ofs), - FSL_SAI_CR2_DIV_MASK, savediv - 1); - } + if (fsl_sai_dir_is_synced(sai, adir)) + reg = FSL_SAI_xCR2(!tx, ofs); + else if (!sai->synchronous[dir]) + reg = FSL_SAI_xCR2(tx, ofs); + else + return 0;
- dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n", - sai->mclk_id[tx], savediv, savesub); + regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_MSEL_MASK, + FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); + regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_DIV_MASK, savediv - 1);
return 0; }
The driver tests for the hardware revision being newer than 3.1 with (sai->verid.major >= 3 && sai->verid.minor >= 1). The result is obviously wrong for hardware revision 4.0. Fix this by storing the full version in a single variable and comparing to that one. No practical change at the moment as there is no 4.0 ip version currently.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- sound/soc/fsl/fsl_sai.c | 8 +++----- sound/soc/fsl/fsl_sai.h | 6 ++---- 2 files changed, 5 insertions(+), 9 deletions(-)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 5f627ccd172b2..2544fd363e24d 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -958,10 +958,8 @@ static int fsl_sai_check_version(struct device *dev)
dev_dbg(dev, "VERID: 0x%016X\n", val);
- sai->verid.major = (val & FSL_SAI_VERID_MAJOR_MASK) >> - FSL_SAI_VERID_MAJOR_SHIFT; - sai->verid.minor = (val & FSL_SAI_VERID_MINOR_MASK) >> - FSL_SAI_VERID_MINOR_SHIFT; + sai->verid.version = val & + (FSL_SAI_VERID_MAJOR_MASK | FSL_SAI_VERID_MINOR_MASK); sai->verid.feature = val & FSL_SAI_VERID_FEATURE_MASK;
ret = regmap_read(sai->regmap, FSL_SAI_PARAM, &val); @@ -1133,7 +1131,7 @@ static int fsl_sai_probe(struct platform_device *pdev)
/* Select MCLK direction */ if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) && - sai->verid.major >= 3 && sai->verid.minor >= 1) { + sai->verid.version >= 0x0301) { regmap_update_bits(sai->regmap, FSL_SAI_MCTL, FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN); } diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 4e76ae43d1968..8c315bf61564d 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -226,15 +226,13 @@ struct fsl_sai_soc_data {
/** * struct fsl_sai_verid - version id data - * @major: major version number - * @minor: minor version number + * @version: version number * @feature: feature specification number * 0000000000000000b - Standard feature set * 0000000000000000b - Standard feature set */ struct fsl_sai_verid { - u32 major; - u32 minor; + u32 version; u32 feature; };
"ret" is normally used as a variable name for return values. In fsl_sai_set_bclk() it stores the difference between the desired rate and the rate we can archieve, so rename it to "diff". Also rename "savesub" to "bestdiff" as that stores the best difference we have found.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- sound/soc/fsl/fsl_sai.c | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 2544fd363e24d..190f6206023fa 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -343,11 +343,10 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); unsigned int reg, ofs = sai->soc_data->reg_offset; unsigned long clk_rate; - u32 savediv = 0, ratio, savesub = freq; + u32 savediv = 0, ratio, bestdiff = freq; int adir = tx ? RX : TX; int dir = tx ? TX : RX; u32 id; - int ret = 0;
/* Don't apply to consumer mode */ if (sai->is_consumer_mode) @@ -361,19 +360,21 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) id = sai->soc_data->mclk0_is_mclk1 ? 1 : 0;
for (; id < FSL_SAI_MCLK_MAX; id++) { + int diff; + clk_rate = clk_get_rate(sai->mclk_clk[id]); if (!clk_rate) continue;
ratio = clk_rate / freq;
- ret = clk_rate - ratio * freq; + diff = clk_rate - ratio * freq;
/* * Drop the source that can not be * divided into the required rate. */ - if (ret != 0 && clk_rate / ret < 1000) + if (diff != 0 && clk_rate / diff < 1000) continue;
dev_dbg(dai->dev, @@ -385,13 +386,13 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) else continue;
- if (ret < savesub) { + if (diff < bestdiff) { savediv = ratio; sai->mclk_id[tx] = id; - savesub = ret; + bestdiff = diff; }
- if (ret == 0) + if (diff == 0) break; }
@@ -402,7 +403,7 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) }
dev_dbg(dai->dev, "best fit: clock id=%d, div=%d, deviation =%d\n", - sai->mclk_id[tx], savediv, savesub); + sai->mclk_id[tx], savediv, bestdiff);
/* * 1) For Asynchronous mode, we must set RCR2 register for capture, and
In fsl_sai_set_bclk() we want to calculate the divider that gets us closest to the desired frequency, so use DIV_ROUND_CLOSEST() instead of just doing a clk_rate/freq. Also discard invalid ratios earlier.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- sound/soc/fsl/fsl_sai.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 190f6206023fa..818bb982427f8 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -366,9 +366,11 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) if (!clk_rate) continue;
- ratio = clk_rate / freq; + ratio = DIV_ROUND_CLOSEST(clk_rate, freq); + if (!ratio || ratio > 512 || ratio & 1) + continue;
- diff = clk_rate - ratio * freq; + diff = abs((long)clk_rate - ratio * freq);
/* * Drop the source that can not be @@ -381,10 +383,6 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) "ratio %d for freq %dHz based on clock %ldHz\n", ratio, freq, clk_rate);
- if (ratio % 2 == 0 && ratio >= 2 && ratio <= 512) - ratio /= 2; - else - continue;
if (diff < bestdiff) { savediv = ratio; @@ -424,7 +422,7 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_MSEL_MASK, FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); - regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_DIV_MASK, savediv - 1); + regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_DIV_MASK, savediv / 2 - 1);
return 0; }
From: Ahmad Fatoum a.fatoum@pengutronix.de
With higher channel counts, we may need higher clock rates. Starting with SAI v3.1 (i.MX8MM), we can bypass the divider and get a 1:1 bclk:mclk ratio. Add the necessary support.
Signed-off-by: Viorel Suman viorel.suman@nxp.com Signed-off-by: Ahmad Fatoum a.fatoum@pengutronix.de Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- sound/soc/fsl/fsl_sai.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index 818bb982427f8..0845f50735248 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -347,6 +347,7 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) int adir = tx ? RX : TX; int dir = tx ? TX : RX; u32 id; + bool support_1_1_ratio = sai->verid.version >= 0x0301;
/* Don't apply to consumer mode */ if (sai->is_consumer_mode) @@ -367,7 +368,11 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) continue;
ratio = DIV_ROUND_CLOSEST(clk_rate, freq); - if (!ratio || ratio > 512 || ratio & 1) + if (!ratio || ratio > 512) + continue; + if (ratio == 1 && !support_1_1_ratio) + continue; + else if (ratio & 1) continue;
diff = abs((long)clk_rate - ratio * freq); @@ -422,7 +427,15 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq)
regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_MSEL_MASK, FSL_SAI_CR2_MSEL(sai->mclk_id[tx])); - regmap_update_bits(sai->regmap, reg, FSL_SAI_CR2_DIV_MASK, savediv / 2 - 1); + + if (savediv == 1) + regmap_update_bits(sai->regmap, reg, + FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP, + FSL_SAI_CR2_BYP); + else + regmap_update_bits(sai->regmap, reg, + FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP, + savediv / 2 - 1);
return 0; }
Hi Sascha,
Can you add Reviewers too? R: Fabio Estevam festevam@gmail.com R: Shengjiu Wang shengjiu.wang@gmail.com
I haven't been working on FSL platforms lately -- will submit a patch to pass my "M:" to Shengjiu.
Thanks Nic
On Wed, Mar 2, 2022 at 12:34 AM Sascha Hauer s.hauer@pengutronix.de wrote:
This series has some updates for the fsl_sai driver: Some general cleanup patches, a bugfix in the ip revision checking and finally the mclk setting is made more accurate and support for 1:1 bclk:mclk setting is added.
Ahmad Fatoum (2): ASoC: fsl_sai: simplify register poking in fsl_sai_set_bclk ASoC: fsl_sai: implement 1:1 bclk:mclk ratio support
Sascha Hauer (5): ASoC: fsl_sai: Drop unnecessary defines ASoC: fsl_sai: simplify irq return value ASoC: fsl_sai: store full version instead of major/minor ASoC: fsl_sai: Use better variable names ASoC: fsl_sai: use DIV_ROUND_CLOSEST() to calculate divider
sound/soc/fsl/fsl_sai.c | 100 ++++++++++++++++++++-------------------- sound/soc/fsl/fsl_sai.h | 9 +--- 2 files changed, 52 insertions(+), 57 deletions(-)
-- 2.30.2
On Wed, 2 Mar 2022 09:34:21 +0100, Sascha Hauer wrote:
This series has some updates for the fsl_sai driver: Some general cleanup patches, a bugfix in the ip revision checking and finally the mclk setting is made more accurate and support for 1:1 bclk:mclk setting is added.
Ahmad Fatoum (2): ASoC: fsl_sai: simplify register poking in fsl_sai_set_bclk ASoC: fsl_sai: implement 1:1 bclk:mclk ratio support
[...]
Applied to
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git for-next
Thanks!
[1/7] ASoC: fsl_sai: Drop unnecessary defines commit: bd393e2ecc30bde95fcfab23af8246d1724e25cd [2/7] ASoC: fsl_sai: simplify irq return value commit: cb00b4c18f89aa8ffb847cd033467f0958c025a0 [3/7] ASoC: fsl_sai: simplify register poking in fsl_sai_set_bclk commit: 814c9fc46fb987bdb3af093e4818c86e62db4fa5 [4/7] ASoC: fsl_sai: store full version instead of major/minor commit: 99c1e74f25d435c1c714b8ee0dceb7ebb7d2f2f1 [5/7] ASoC: fsl_sai: Use better variable names commit: c56359f4f2adfb81cf7cbea1e8ef9bfc59dbd4ec [6/7] ASoC: fsl_sai: use DIV_ROUND_CLOSEST() to calculate divider commit: 1d4cbdf7bf2eaa794528250a29aed08f1df7f837 [7/7] ASoC: fsl_sai: implement 1:1 bclk:mclk ratio support commit: a50b7926d015c3b8194ab1d7c8aa86db8e4b7700
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
participants (3)
-
Mark Brown
-
Nicolin Chen
-
Sascha Hauer