From bd393e2ecc30bde95fcfab23af8246d1724e25cd Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 2 Mar 2022 09:34:22 +0100 Subject: ASoC: fsl_sai: Drop unnecessary defines 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 Link: https://lore.kernel.org/r/20220302083428.3804687-2-s.hauer@pengutronix.de Signed-off-by: Mark Brown --- 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 c2d423d1d87e..9b43f94f672f 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 410f6e6a9137..b30d6113ff08 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 -- cgit v1.2.3 From cb00b4c18f89aa8ffb847cd033467f0958c025a0 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 2 Mar 2022 09:34:23 +0100 Subject: ASoC: fsl_sai: simplify irq return value 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 Link: https://lore.kernel.org/r/20220302083428.3804687-3-s.hauer@pengutronix.de Signed-off-by: Mark Brown --- 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 9b43f94f672f..b815e868567b 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 @@ irq_rx: flags = xcsr & mask; if (flags) - irq_none = false; + iret = IRQ_HANDLED; else goto out; @@ -139,10 +139,7 @@ irq_rx: 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, -- cgit v1.2.3 From 814c9fc46fb987bdb3af093e4818c86e62db4fa5 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 2 Mar 2022 09:34:24 +0100 Subject: ASoC: fsl_sai: simplify register poking in fsl_sai_set_bclk 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 Signed-off-by: Sascha Hauer Link: https://lore.kernel.org/r/20220302083428.3804687-4-s.hauer@pengutronix.de Signed-off-by: Mark Brown --- 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 b815e868567b..218282c2e86f 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; } -- cgit v1.2.3 From 99c1e74f25d435c1c714b8ee0dceb7ebb7d2f2f1 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 2 Mar 2022 09:34:25 +0100 Subject: ASoC: fsl_sai: store full version instead of major/minor 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 Link: https://lore.kernel.org/r/20220302083428.3804687-5-s.hauer@pengutronix.de Signed-off-by: Mark Brown --- 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 218282c2e86f..c9341c25edf1 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -962,10 +962,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); @@ -1137,7 +1135,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 b30d6113ff08..7310fd02cc3c 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -227,15 +227,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; }; -- cgit v1.2.3 From c56359f4f2adfb81cf7cbea1e8ef9bfc59dbd4ec Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 2 Mar 2022 09:34:26 +0100 Subject: ASoC: fsl_sai: Use better variable names "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 Link: https://lore.kernel.org/r/20220302083428.3804687-6-s.hauer@pengutronix.de Signed-off-by: Mark Brown --- 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 c9341c25edf1..02b4cffa8455 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 -- cgit v1.2.3 From 1d4cbdf7bf2eaa794528250a29aed08f1df7f837 Mon Sep 17 00:00:00 2001 From: Sascha Hauer Date: Wed, 2 Mar 2022 09:34:27 +0100 Subject: ASoC: fsl_sai: use DIV_ROUND_CLOSEST() to calculate divider 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 Link: https://lore.kernel.org/r/20220302083428.3804687-7-s.hauer@pengutronix.de Signed-off-by: Mark Brown --- 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 02b4cffa8455..761fa8229a09 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; } -- cgit v1.2.3 From a50b7926d015c3b8194ab1d7c8aa86db8e4b7700 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 2 Mar 2022 09:34:28 +0100 Subject: ASoC: fsl_sai: implement 1:1 bclk:mclk ratio support 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 Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer Link: https://lore.kernel.org/r/20220302083428.3804687-8-s.hauer@pengutronix.de Signed-off-by: Mark Brown --- 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 761fa8229a09..4650a6931a94 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; } -- cgit v1.2.3