diff options
Diffstat (limited to 'sound/soc/fsl')
-rw-r--r-- | sound/soc/fsl/Kconfig | 3 | ||||
-rw-r--r-- | sound/soc/fsl/fsl-asoc-card.c | 5 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_asrc.c | 6 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_asrc_dma.c | 19 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_aud2htx.c | 3 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_audmix.c | 6 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_easrc.c | 16 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_easrc.h | 2 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_esai.c | 11 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_micfil.c | 55 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_micfil.h | 9 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_mqs.c | 136 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_rpmsg.c | 3 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_sai.c | 376 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_sai.h | 28 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_spdif.c | 51 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_ssi.c | 23 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_utils.c | 69 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_utils.h | 7 | ||||
-rw-r--r-- | sound/soc/fsl/fsl_xcvr.c | 12 | ||||
-rw-r--r-- | sound/soc/fsl/imx-audmix.c | 4 | ||||
-rw-r--r-- | sound/soc/fsl/imx-audmux.c | 24 | ||||
-rw-r--r-- | sound/soc/fsl/imx-card.c | 24 | ||||
-rw-r--r-- | sound/soc/fsl/mpc5200_psc_i2s.c | 3 | ||||
-rw-r--r-- | sound/soc/fsl/pcm030-audio-fabric.c | 8 |
25 files changed, 721 insertions, 182 deletions
diff --git a/sound/soc/fsl/Kconfig b/sound/soc/fsl/Kconfig index 10fa38753453..614eceda6b9e 100644 --- a/sound/soc/fsl/Kconfig +++ b/sound/soc/fsl/Kconfig @@ -19,6 +19,7 @@ config SND_SOC_FSL_SAI select REGMAP_MMIO select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_SOC_FSL_UTILS help Say Y if you want to add Synchronous Audio Interface (SAI) support for the Freescale CPUs. @@ -59,6 +60,7 @@ config SND_SOC_FSL_SPDIF select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n select SND_SOC_IMX_PCM_FIQ if SND_IMX_SOC != n && (MXC_TZIC || MXC_AVIC) select BITREVERSE + select SND_SOC_FSL_UTILS help Say Y if you want to add Sony/Philips Digital Interface (SPDIF) support for the Freescale CPUs. @@ -80,6 +82,7 @@ config SND_SOC_FSL_MICFIL select REGMAP_MMIO select SND_SOC_IMX_PCM_DMA if SND_IMX_SOC != n select SND_SOC_GENERIC_DMAENGINE_PCM + select SND_SOC_FSL_UTILS help Say Y if you want to add Pulse Density Modulation microphone interface (MICFIL) support for NXP. diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c index d9a0d4768c4d..c836848ef0a6 100644 --- a/sound/soc/fsl/fsl-asoc-card.c +++ b/sound/soc/fsl/fsl-asoc-card.c @@ -537,6 +537,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) struct device *codec_dev = NULL; const char *codec_dai_name; const char *codec_dev_name; + u32 asrc_fmt = 0; u32 width; int ret; @@ -829,8 +830,8 @@ static int fsl_asoc_card_probe(struct platform_device *pdev) goto asrc_fail; } - ret = of_property_read_u32(asrc_np, "fsl,asrc-format", - &priv->asrc_format); + ret = of_property_read_u32(asrc_np, "fsl,asrc-format", &asrc_fmt); + priv->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { /* Fallback to old binding; translate to asrc_format */ ret = of_property_read_u32(asrc_np, "fsl,asrc-width", diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index 20a9f8e924b3..aa5edf32d988 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -1066,6 +1066,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) struct resource *res; void __iomem *regs; int irq, ret, i; + u32 asrc_fmt = 0; u32 map_idx; char tmp[16]; u32 width; @@ -1174,7 +1175,8 @@ static int fsl_asrc_probe(struct platform_device *pdev) return ret; } - ret = of_property_read_u32(np, "fsl,asrc-format", &asrc->asrc_format); + ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt); + asrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { ret = of_property_read_u32(np, "fsl,asrc-width", &width); if (ret) { @@ -1197,7 +1199,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) } } - if (!(FSL_ASRC_FORMATS & (1ULL << asrc->asrc_format))) { + if (!(FSL_ASRC_FORMATS & pcm_format_to_bits(asrc->asrc_format))) { dev_warn(&pdev->dev, "unsupported width, use default S24_LE\n"); asrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; } diff --git a/sound/soc/fsl/fsl_asrc_dma.c b/sound/soc/fsl/fsl_asrc_dma.c index 5038faf035cb..12ddf2320f2d 100644 --- a/sound/soc/fsl/fsl_asrc_dma.c +++ b/sound/soc/fsl/fsl_asrc_dma.c @@ -114,8 +114,8 @@ static int fsl_asrc_dma_trigger(struct snd_soc_component *component, case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: - dmaengine_terminate_all(pair->dma_chan[OUT]); - dmaengine_terminate_all(pair->dma_chan[IN]); + dmaengine_terminate_async(pair->dma_chan[OUT]); + dmaengine_terminate_async(pair->dma_chan[IN]); break; default: return -EINVAL; @@ -129,6 +129,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, struct snd_pcm_hw_params *params) { enum dma_slave_buswidth buswidth = DMA_SLAVE_BUSWIDTH_2_BYTES; + enum sdma_peripheral_type be_peripheral_type = IMX_DMATYPE_SSI; struct snd_soc_pcm_runtime *rtd = asoc_substream_to_rtd(substream); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; struct snd_dmaengine_dai_dma_data *dma_params_fe = NULL; @@ -139,6 +140,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, struct snd_soc_component *component_be = NULL; struct fsl_asrc *asrc = pair->asrc; struct dma_slave_config config_fe, config_be; + struct sdma_peripheral_config audio_config; enum asrc_pair_index index = pair->index; struct device *dev = component->dev; struct device_node *of_dma_node; @@ -221,6 +223,7 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, /* Get DMA request of Back-End */ tmp_data = tmp_chan->private; pair->dma_data.dma_request = tmp_data->dma_request; + be_peripheral_type = tmp_data->peripheral_type; if (!be_chan) dma_release_channel(tmp_chan); @@ -268,6 +271,17 @@ static int fsl_asrc_dma_hw_params(struct snd_soc_component *component, config_be.dst_addr_width = buswidth; config_be.dst_maxburst = dma_params_be->maxburst; + memset(&audio_config, 0, sizeof(audio_config)); + config_be.peripheral_config = &audio_config; + config_be.peripheral_size = sizeof(audio_config); + + if (tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL || + be_peripheral_type == IMX_DMATYPE_SPDIF)) + audio_config.n_fifos_dst = 2; + if (!tx && (be_peripheral_type == IMX_DMATYPE_SSI_DUAL || + be_peripheral_type == IMX_DMATYPE_SPDIF)) + audio_config.n_fifos_src = 2; + if (tx) { config_be.src_addr = asrc->paddr + asrc->get_fifo_addr(OUT, index); config_be.dst_addr = dma_params_be->addr; @@ -441,5 +455,6 @@ struct snd_soc_component_driver fsl_asrc_component = { .close = fsl_asrc_dma_shutdown, .pointer = fsl_asrc_dma_pcm_pointer, .pcm_construct = fsl_asrc_dma_pcm_new, + .legacy_dai_naming = 1, }; EXPORT_SYMBOL_GPL(fsl_asrc_component); diff --git a/sound/soc/fsl/fsl_aud2htx.c b/sound/soc/fsl/fsl_aud2htx.c index 422922146f2a..873295f59ad7 100644 --- a/sound/soc/fsl/fsl_aud2htx.c +++ b/sound/soc/fsl/fsl_aud2htx.c @@ -103,7 +103,8 @@ static struct snd_soc_dai_driver fsl_aud2htx_dai = { }; static const struct snd_soc_component_driver fsl_aud2htx_component = { - .name = "fsl-aud2htx", + .name = "fsl-aud2htx", + .legacy_dai_naming = 1, }; static const struct reg_default fsl_aud2htx_reg_defaults[] = { diff --git a/sound/soc/fsl/fsl_audmix.c b/sound/soc/fsl/fsl_audmix.c index 6dbb8c99f626..43857b7a81c9 100644 --- a/sound/soc/fsl/fsl_audmix.c +++ b/sound/soc/fsl/fsl_audmix.c @@ -259,8 +259,8 @@ static int fsl_audmix_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* For playback the AUDMIX is consumer, and for record is provider */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BC_FC: + case SND_SOC_DAIFMT_BP_FP: break; default: return -EINVAL; @@ -317,7 +317,7 @@ static int fsl_audmix_dai_trigger(struct snd_pcm_substream *substream, int cmd, } static const struct snd_soc_dai_ops fsl_audmix_dai_ops = { - .set_fmt = fsl_audmix_dai_set_fmt, + .set_fmt = fsl_audmix_dai_set_fmt, .trigger = fsl_audmix_dai_trigger, }; diff --git a/sound/soc/fsl/fsl_easrc.c b/sound/soc/fsl/fsl_easrc.c index be14f84796cb..3153d19136b2 100644 --- a/sound/soc/fsl/fsl_easrc.c +++ b/sound/soc/fsl/fsl_easrc.c @@ -476,7 +476,8 @@ static int fsl_easrc_prefilter_config(struct fsl_asrc *easrc, struct fsl_asrc_pair *ctx; struct device *dev; u32 inrate, outrate, offset = 0; - u32 in_s_rate, out_s_rate, in_s_fmt, out_s_fmt; + u32 in_s_rate, out_s_rate; + snd_pcm_format_t in_s_fmt, out_s_fmt; int ret, i; if (!easrc) @@ -1572,9 +1573,10 @@ static struct snd_soc_dai_driver fsl_easrc_dai = { }; static const struct snd_soc_component_driver fsl_easrc_component = { - .name = "fsl-easrc-dai", - .controls = fsl_easrc_snd_controls, - .num_controls = ARRAY_SIZE(fsl_easrc_snd_controls), + .name = "fsl-easrc-dai", + .controls = fsl_easrc_snd_controls, + .num_controls = ARRAY_SIZE(fsl_easrc_snd_controls), + .legacy_dai_naming = 1, }; static const struct reg_default fsl_easrc_reg_defaults[] = { @@ -1873,6 +1875,7 @@ static int fsl_easrc_probe(struct platform_device *pdev) struct resource *res; struct device_node *np; void __iomem *regs; + u32 asrc_fmt = 0; int ret, irq; easrc = devm_kzalloc(dev, sizeof(*easrc), GFP_KERNEL); @@ -1933,13 +1936,14 @@ static int fsl_easrc_probe(struct platform_device *pdev) return ret; } - ret = of_property_read_u32(np, "fsl,asrc-format", &easrc->asrc_format); + ret = of_property_read_u32(np, "fsl,asrc-format", &asrc_fmt); + easrc->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { dev_err(dev, "failed to asrc format\n"); return ret; } - if (!(FSL_EASRC_FORMATS & (1ULL << easrc->asrc_format))) { + if (!(FSL_EASRC_FORMATS & (pcm_format_to_bits(easrc->asrc_format)))) { dev_warn(dev, "unsupported format, switching to S24_LE\n"); easrc->asrc_format = SNDRV_PCM_FORMAT_S24_LE; } diff --git a/sound/soc/fsl/fsl_easrc.h b/sound/soc/fsl/fsl_easrc.h index 86d5c360d4f5..7c70dac52713 100644 --- a/sound/soc/fsl/fsl_easrc.h +++ b/sound/soc/fsl/fsl_easrc.h @@ -569,7 +569,7 @@ struct fsl_easrc_io_params { unsigned int access_len; unsigned int fifo_wtmk; unsigned int sample_rate; - unsigned int sample_format; + snd_pcm_format_t sample_format; unsigned int norm_rate; }; diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c index 1a2bdf8e76f0..5c21fc490fce 100644 --- a/sound/soc/fsl/fsl_esai.c +++ b/sound/soc/fsl/fsl_esai.c @@ -480,16 +480,16 @@ static int fsl_esai_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) /* DAI clock provider masks */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: esai_priv->consumer_mode = true; break; - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BP_FC: xccr |= ESAI_xCCR_xCKD; break; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: xccr |= ESAI_xCCR_xFSD; break; - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: xccr |= ESAI_xCCR_xFSD | ESAI_xCCR_xCKD; break; default: @@ -824,7 +824,8 @@ static struct snd_soc_dai_driver fsl_esai_dai = { }; static const struct snd_soc_component_driver fsl_esai_component = { - .name = "fsl-esai", + .name = "fsl-esai", + .legacy_dai_naming = 1, }; static const struct reg_default fsl_esai_reg_defaults[] = { diff --git a/sound/soc/fsl/fsl_micfil.c b/sound/soc/fsl/fsl_micfil.c index 7b88d52f27de..79ef4e269bc9 100644 --- a/sound/soc/fsl/fsl_micfil.c +++ b/sound/soc/fsl/fsl_micfil.c @@ -24,6 +24,7 @@ #include <sound/core.h> #include "fsl_micfil.h" +#include "fsl_utils.h" #define MICFIL_OSR_DEFAULT 16 @@ -42,12 +43,15 @@ struct fsl_micfil { const struct fsl_micfil_soc_data *soc; struct clk *busclk; struct clk *mclk; + struct clk *pll8k_clk; + struct clk *pll11k_clk; struct snd_dmaengine_dai_dma_data dma_params_rx; struct sdma_peripheral_config sdmacfg; unsigned int dataline; char name[32]; int irq[MICFIL_IRQ_LINES]; enum quality quality; + int dc_remover; }; struct fsl_micfil_soc_data { @@ -263,6 +267,27 @@ static int fsl_micfil_trigger(struct snd_pcm_substream *substream, int cmd, return 0; } +static int fsl_micfil_reparent_rootclk(struct fsl_micfil *micfil, unsigned int sample_rate) +{ + struct device *dev = &micfil->pdev->dev; + u64 ratio = sample_rate; + struct clk *clk; + int ret; + + /* Get root clock */ + clk = micfil->mclk; + + /* Disable clock first, for it was enabled by pm_runtime */ + clk_disable_unprepare(clk); + fsl_asoc_reparent_pll_clocks(dev, clk, micfil->pll8k_clk, + micfil->pll11k_clk, ratio); + ret = clk_prepare_enable(clk); + if (ret) + return ret; + + return 0; +} + static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -286,6 +311,10 @@ static int fsl_micfil_hw_params(struct snd_pcm_substream *substream, if (ret) return ret; + ret = fsl_micfil_reparent_rootclk(micfil, rate); + if (ret) + return ret; + ret = clk_set_rate(micfil->mclk, rate * clk_div * osr * 8); if (ret) return ret; @@ -317,12 +346,25 @@ static const struct snd_soc_dai_ops fsl_micfil_dai_ops = { static int fsl_micfil_dai_probe(struct snd_soc_dai *cpu_dai) { struct fsl_micfil *micfil = dev_get_drvdata(cpu_dai->dev); - int ret; + struct device *dev = cpu_dai->dev; + unsigned int val = 0; + int ret, i; - micfil->quality = QUALITY_MEDIUM; + micfil->quality = QUALITY_VLOW0; - /* set default gain to max_gain */ - regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x77777777); + /* set default gain to 2 */ + regmap_write(micfil->regmap, REG_MICFIL_OUT_CTRL, 0x22222222); + + /* set DC Remover in bypass mode*/ + for (i = 0; i < MICFIL_OUTPUT_CHANNELS; i++) + val |= MICFIL_DC_BYPASS << MICFIL_DC_CHX_SHIFT(i); + ret = regmap_update_bits(micfil->regmap, REG_MICFIL_DC_CTRL, + MICFIL_DC_CTRL_CONFIG, val); + if (ret) { + dev_err(dev, "failed to set DC Remover mode bits\n"); + return ret; + } + micfil->dc_remover = MICFIL_DC_BYPASS; snd_soc_dai_init_dma_data(cpu_dai, NULL, &micfil->dma_params_rx); @@ -353,7 +395,7 @@ static const struct snd_soc_component_driver fsl_micfil_component = { .name = "fsl-micfil-dai", .controls = fsl_micfil_snd_controls, .num_controls = ARRAY_SIZE(fsl_micfil_snd_controls), - + .legacy_dai_naming = 1, }; /* REGMAP */ @@ -577,6 +619,9 @@ static int fsl_micfil_probe(struct platform_device *pdev) return PTR_ERR(micfil->busclk); } + fsl_asoc_get_pll_clocks(&pdev->dev, &micfil->pll8k_clk, + &micfil->pll11k_clk); + /* init regmap */ regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res); if (IS_ERR(regs)) diff --git a/sound/soc/fsl/fsl_micfil.h b/sound/soc/fsl/fsl_micfil.h index 053caba3caf3..d60285dd07bc 100644 --- a/sound/soc/fsl/fsl_micfil.h +++ b/sound/soc/fsl/fsl_micfil.h @@ -73,6 +73,15 @@ #define MICFIL_FIFO_STAT_FIFOX_OVER(ch) BIT(ch) #define MICFIL_FIFO_STAT_FIFOX_UNDER(ch) BIT((ch) + 8) +/* MICFIL DC Remover Control Register -- REG_MICFIL_DC_CTRL */ +#define MICFIL_DC_CTRL_CONFIG GENMASK(15, 0) +#define MICFIL_DC_CHX_SHIFT(ch) ((ch) << 1) +#define MICFIL_DC_CHX(ch) GENMASK((((ch) << 1) + 1), ((ch) << 1)) +#define MICFIL_DC_CUTOFF_21HZ 0 +#define MICFIL_DC_CUTOFF_83HZ 1 +#define MICFIL_DC_CUTOFF_152Hz 2 +#define MICFIL_DC_BYPASS 3 + /* MICFIL HWVAD0 Control 1 Register -- REG_MICFIL_VAD0_CTRL1*/ #define MICFIL_VAD0_CTRL1_CHSEL GENMASK(26, 24) #define MICFIL_VAD0_CTRL1_CICOSR GENMASK(19, 16) diff --git a/sound/soc/fsl/fsl_mqs.c b/sound/soc/fsl/fsl_mqs.c index ceaecbe3a25e..c1e2f671191b 100644 --- a/sound/soc/fsl/fsl_mqs.c +++ b/sound/soc/fsl/fsl_mqs.c @@ -10,6 +10,7 @@ #include <linux/moduleparam.h> #include <linux/mfd/syscon.h> #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> +#include <linux/of_device.h> #include <linux/pm_runtime.h> #include <linux/of.h> #include <linux/pm.h> @@ -29,15 +30,41 @@ #define MQS_CLK_DIV_MASK (0xFF << 0) #define MQS_CLK_DIV_SHIFT (0) +/** + * struct fsl_mqs_soc_data - soc specific data + * + * @use_gpr: control register is in General Purpose Register group + * @ctrl_off: control register offset + * @en_mask: enable bit mask + * @en_shift: enable bit shift + * @rst_mask: reset bit mask + * @rst_shift: reset bit shift + * @osr_mask: oversample bit mask + * @osr_shift: oversample bit shift + * @div_mask: clock divider mask + * @div_shift: clock divider bit shift + */ +struct fsl_mqs_soc_data { + bool use_gpr; + int ctrl_off; + int en_mask; + int en_shift; + int rst_mask; + int rst_shift; + int osr_mask; + int osr_shift; + int div_mask; + int div_shift; +}; + /* codec private data */ struct fsl_mqs { struct regmap *regmap; struct clk *mclk; struct clk *ipg; + const struct fsl_mqs_soc_data *soc; - unsigned int reg_iomuxc_gpr2; unsigned int reg_mqs_ctrl; - bool use_gpr; }; #define FSL_MQS_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000) @@ -65,19 +92,11 @@ static int fsl_mqs_hw_params(struct snd_pcm_substream *substream, res = mclk_rate % (32 * lrclk * 2 * 8); if (res == 0 && div > 0 && div <= 256) { - if (mqs_priv->use_gpr) { - regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, - IMX6SX_GPR2_MQS_CLK_DIV_MASK, - (div - 1) << IMX6SX_GPR2_MQS_CLK_DIV_SHIFT); - regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, - IMX6SX_GPR2_MQS_OVERSAMPLE_MASK, 0); - } else { - regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, - MQS_CLK_DIV_MASK, - (div - 1) << MQS_CLK_DIV_SHIFT); - regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, - MQS_OVERSAMPLE_MASK, 0); - } + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, + mqs_priv->soc->div_mask, + (div - 1) << mqs_priv->soc->div_shift); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, + mqs_priv->soc->osr_mask, 0); } else { dev_err(component->dev, "can't get proper divider\n"); } @@ -103,7 +122,7 @@ static int fsl_mqs_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt) } switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: break; default: return -EINVAL; @@ -118,14 +137,9 @@ static int fsl_mqs_startup(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component); - if (mqs_priv->use_gpr) - regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, - IMX6SX_GPR2_MQS_EN_MASK, - 1 << IMX6SX_GPR2_MQS_EN_SHIFT); - else - regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, - MQS_EN_MASK, - 1 << MQS_EN_SHIFT); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, + mqs_priv->soc->en_mask, + 1 << mqs_priv->soc->en_shift); return 0; } @@ -135,17 +149,12 @@ static void fsl_mqs_shutdown(struct snd_pcm_substream *substream, struct snd_soc_component *component = dai->component; struct fsl_mqs *mqs_priv = snd_soc_component_get_drvdata(component); - if (mqs_priv->use_gpr) - regmap_update_bits(mqs_priv->regmap, IOMUXC_GPR2, - IMX6SX_GPR2_MQS_EN_MASK, 0); - else - regmap_update_bits(mqs_priv->regmap, REG_MQS_CTRL, - MQS_EN_MASK, 0); + regmap_update_bits(mqs_priv->regmap, mqs_priv->soc->ctrl_off, + mqs_priv->soc->en_mask, 0); } static const struct snd_soc_component_driver soc_codec_fsl_mqs = { .idle_bias_on = 1, - .non_legacy_dai_naming = 1, }; static const struct snd_soc_dai_ops fsl_mqs_dai_ops = { @@ -191,12 +200,9 @@ static int fsl_mqs_probe(struct platform_device *pdev) * But in i.MX8QM/i.MX8QXP the control register is moved * to its own domain. */ - if (of_device_is_compatible(np, "fsl,imx8qm-mqs")) - mqs_priv->use_gpr = false; - else - mqs_priv->use_gpr = true; + mqs_priv->soc = of_device_get_match_data(&pdev->dev); - if (mqs_priv->use_gpr) { + if (mqs_priv->soc->use_gpr) { gpr_np = of_parse_phandle(np, "gpr", 0); if (!gpr_np) { dev_err(&pdev->dev, "failed to get gpr node by phandle\n"); @@ -280,12 +286,7 @@ static int fsl_mqs_runtime_resume(struct device *dev) return ret; } - if (mqs_priv->use_gpr) - regmap_write(mqs_priv->regmap, IOMUXC_GPR2, - mqs_priv->reg_iomuxc_gpr2); - else - regmap_write(mqs_priv->regmap, REG_MQS_CTRL, - mqs_priv->reg_mqs_ctrl); + regmap_write(mqs_priv->regmap, mqs_priv->soc->ctrl_off, mqs_priv->reg_mqs_ctrl); return 0; } @@ -293,12 +294,7 @@ static int fsl_mqs_runtime_suspend(struct device *dev) { struct fsl_mqs *mqs_priv = dev_get_drvdata(dev); - if (mqs_priv->use_gpr) - regmap_read(mqs_priv->regmap, IOMUXC_GPR2, - &mqs_priv->reg_iomuxc_gpr2); - else - regmap_read(mqs_priv->regmap, REG_MQS_CTRL, - &mqs_priv->reg_mqs_ctrl); + regmap_read(mqs_priv->regmap, mqs_priv->soc->ctrl_off, &mqs_priv->reg_mqs_ctrl); clk_disable_unprepare(mqs_priv->mclk); clk_disable_unprepare(mqs_priv->ipg); @@ -315,9 +311,49 @@ static const struct dev_pm_ops fsl_mqs_pm_ops = { pm_runtime_force_resume) }; +static const struct fsl_mqs_soc_data fsl_mqs_imx8qm_data = { + .use_gpr = false, + .ctrl_off = REG_MQS_CTRL, + .en_mask = MQS_EN_MASK, + .en_shift = MQS_EN_SHIFT, + .rst_mask = MQS_SW_RST_MASK, + .rst_shift = MQS_SW_RST_SHIFT, + .osr_mask = MQS_OVERSAMPLE_MASK, + .osr_shift = MQS_OVERSAMPLE_SHIFT, + .div_mask = MQS_CLK_DIV_MASK, + .div_shift = MQS_CLK_DIV_SHIFT, +}; + +static const struct fsl_mqs_soc_data fsl_mqs_imx6sx_data = { + .use_gpr = true, + .ctrl_off = IOMUXC_GPR2, + .en_mask = IMX6SX_GPR2_MQS_EN_MASK, + .en_shift = IMX6SX_GPR2_MQS_EN_SHIFT, + .rst_mask = IMX6SX_GPR2_MQS_SW_RST_MASK, + .rst_shift = IMX6SX_GPR2_MQS_SW_RST_SHIFT, + .osr_mask = IMX6SX_GPR2_MQS_OVERSAMPLE_MASK, + .osr_shift = IMX6SX_GPR2_MQS_OVERSAMPLE_SHIFT, + .div_mask = IMX6SX_GPR2_MQS_CLK_DIV_MASK, + .div_shift = IMX6SX_GPR2_MQS_CLK_DIV_SHIFT, +}; + +static const struct fsl_mqs_soc_data fsl_mqs_imx93_data = { + .use_gpr = true, + .ctrl_off = 0x20, + .en_mask = BIT(1), + .en_shift = 1, + .rst_mask = BIT(2), + .rst_shift = 2, + .osr_mask = BIT(3), + .osr_shift = 3, + .div_mask = GENMASK(15, 8), + .div_shift = 8, +}; + static const struct of_device_id fsl_mqs_dt_ids[] = { - { .compatible = "fsl,imx8qm-mqs", }, - { .compatible = "fsl,imx6sx-mqs", }, + { .compatible = "fsl,imx8qm-mqs", .data = &fsl_mqs_imx8qm_data }, + { .compatible = "fsl,imx6sx-mqs", .data = &fsl_mqs_imx6sx_data }, + { .compatible = "fsl,imx93-mqs", .data = &fsl_mqs_imx93_data }, {} }; MODULE_DEVICE_TABLE(of, fsl_mqs_dt_ids); diff --git a/sound/soc/fsl/fsl_rpmsg.c b/sound/soc/fsl/fsl_rpmsg.c index 19fd31250883..bf94838bdbef 100644 --- a/sound/soc/fsl/fsl_rpmsg.c +++ b/sound/soc/fsl/fsl_rpmsg.c @@ -135,7 +135,8 @@ static struct snd_soc_dai_driver fsl_rpmsg_dai = { }; static const struct snd_soc_component_driver fsl_component = { - .name = "fsl-rpmsg", + .name = "fsl-rpmsg", + .legacy_dai_naming = 1, }; static const struct fsl_rpmsg_soc_data imx7ulp_data = { diff --git a/sound/soc/fsl/fsl_sai.c b/sound/soc/fsl/fsl_sai.c index fa950dde5310..7523bb944b21 100644 --- a/sound/soc/fsl/fsl_sai.c +++ b/sound/soc/fsl/fsl_sai.c @@ -10,6 +10,7 @@ #include <linux/module.h> #include <linux/of_address.h> #include <linux/of_device.h> +#include <linux/pinctrl/consumer.h> #include <linux/pm_qos.h> #include <linux/pm_runtime.h> #include <linux/regmap.h> @@ -22,6 +23,7 @@ #include <linux/mfd/syscon/imx6q-iomuxc-gpr.h> #include "fsl_sai.h" +#include "fsl_utils.h" #include "imx-pcm.h" #define FSL_SAI_FLAGS (FSL_SAI_CSR_SEIE |\ @@ -30,7 +32,8 @@ static const unsigned int fsl_sai_rates[] = { 8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100, 48000, 64000, - 88200, 96000, 176400, 192000 + 88200, 96000, 176400, 192000, 352800, + 384000, 705600, 768000, 1411200, 2822400, }; static const struct snd_pcm_hw_constraint_list fsl_sai_rate_constraints = { @@ -56,6 +59,31 @@ static inline bool fsl_sai_dir_is_synced(struct fsl_sai *sai, int dir) return !sai->synchronous[dir] && sai->synchronous[adir]; } +static struct pinctrl_state *fsl_sai_get_pins_state(struct fsl_sai *sai, u32 bclk) +{ + struct pinctrl_state *state = NULL; + + if (sai->is_pdm_mode) { + /* DSD512@44.1kHz, DSD512@48kHz */ + if (bclk >= 22579200) + state = pinctrl_lookup_state(sai->pinctrl, "dsd512"); + + /* Get default DSD state */ + if (IS_ERR_OR_NULL(state)) + state = pinctrl_lookup_state(sai->pinctrl, "dsd"); + } else { + /* 706k32b2c, 768k32b2c, etc */ + if (bclk >= 45158400) + state = pinctrl_lookup_state(sai->pinctrl, "pcm_b2m"); + } + + /* Get default state */ + if (IS_ERR_OR_NULL(state)) + state = pinctrl_lookup_state(sai->pinctrl, "default"); + + return state; +} + static irqreturn_t fsl_sai_isr(int irq, void *devid) { struct fsl_sai *sai = (struct fsl_sai *)devid; @@ -193,14 +221,48 @@ static int fsl_sai_set_dai_sysclk_tr(struct snd_soc_dai *cpu_dai, return 0; } +static int fsl_sai_set_mclk_rate(struct snd_soc_dai *dai, int clk_id, unsigned int freq) +{ + struct fsl_sai *sai = snd_soc_dai_get_drvdata(dai); + int ret; + + fsl_asoc_reparent_pll_clocks(dai->dev, sai->mclk_clk[clk_id], + sai->pll8k_clk, sai->pll11k_clk, freq); + + ret = clk_set_rate(sai->mclk_clk[clk_id], freq); + if (ret < 0) + dev_err(dai->dev, "failed to set clock rate (%u): %d\n", freq, ret); + + return ret; +} + static int fsl_sai_set_dai_sysclk(struct snd_soc_dai *cpu_dai, int clk_id, unsigned int freq, int dir) { + struct fsl_sai *sai = snd_soc_dai_get_drvdata(cpu_dai); int ret; if (dir == SND_SOC_CLOCK_IN) return 0; + if (freq > 0 && clk_id != FSL_SAI_CLK_BUS) { + if (clk_id < 0 || clk_id >= FSL_SAI_MCLK_MAX) { + dev_err(cpu_dai->dev, "Unknown clock id: %d\n", clk_id); + return -EINVAL; + } + + if (IS_ERR_OR_NULL(sai->mclk_clk[clk_id])) { + dev_err(cpu_dai->dev, "Unassigned clock: %d\n", clk_id); + return -EINVAL; + } + + if (sai->mclk_streams == 0) { + ret = fsl_sai_set_mclk_rate(cpu_dai, clk_id, freq); + if (ret < 0) + return ret; + } + } + 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); @@ -224,6 +286,7 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, if (!sai->is_lsb_first) val_cr4 |= FSL_SAI_CR4_MF; + sai->is_pdm_mode = false; /* DAI mode */ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: @@ -262,6 +325,11 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, val_cr2 |= FSL_SAI_CR2_BCP; sai->is_dsp_mode = true; break; + case SND_SOC_DAIFMT_PDM: + val_cr2 |= FSL_SAI_CR2_BCP; + val_cr4 &= ~FSL_SAI_CR4_MF; + sai->is_pdm_mode = true; + break; case SND_SOC_DAIFMT_RIGHT_J: /* To be done */ default: @@ -292,19 +360,19 @@ static int fsl_sai_set_dai_fmt_tr(struct snd_soc_dai *cpu_dai, /* DAI clock provider masks */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; val_cr4 |= FSL_SAI_CR4_FSD_MSTR; sai->is_consumer_mode = false; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: sai->is_consumer_mode = true; break; - case SND_SOC_DAIFMT_CBC_CFP: + case SND_SOC_DAIFMT_BP_FC: val_cr2 |= FSL_SAI_CR2_BCD_MSTR; sai->is_consumer_mode = false; break; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: val_cr4 |= FSL_SAI_CR4_FSD_MSTR; sai->is_consumer_mode = true; break; @@ -437,6 +505,12 @@ static int fsl_sai_set_bclk(struct snd_soc_dai *dai, bool tx, u32 freq) FSL_SAI_CR2_DIV_MASK | FSL_SAI_CR2_BYP, savediv / 2 - 1); + if (sai->soc_data->max_register >= FSL_SAI_MCTL) { + /* SAI is in master mode at this point, so enable MCLK */ + regmap_update_bits(sai->regmap, FSL_SAI_MCTL, + FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN); + } + return 0; } @@ -448,13 +522,18 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, unsigned int ofs = sai->soc_data->reg_offset; bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; unsigned int channels = params_channels(params); + struct snd_dmaengine_dai_dma_data *dma_params; + struct fsl_sai_dl_cfg *dl_cfg = sai->dl_cfg; u32 word_width = params_width(params); + int trce_mask = 0, dl_cfg_idx = 0; + int dl_cfg_cnt = sai->dl_cfg_cnt; + u32 dl_type = FSL_SAI_DL_I2S; u32 val_cr4 = 0, val_cr5 = 0; u32 slots = (channels == 1) ? 2 : channels; u32 slot_width = word_width; int adir = tx ? RX : TX; - u32 pins; - int ret; + u32 pins, bclk; + int ret, i; if (sai->slots) slots = sai->slots; @@ -464,15 +543,42 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, pins = DIV_ROUND_UP(channels, slots); + /* + * PDM mode, channels are independent + * each channels are on one dataline/FIFO. + */ + if (sai->is_pdm_mode) { + pins = channels; + dl_type = FSL_SAI_DL_PDM; + } + + for (i = 0; i < dl_cfg_cnt; i++) { + if (dl_cfg[i].type == dl_type && dl_cfg[i].pins[tx] == pins) { + dl_cfg_idx = i; + break; + } + } + + if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) < pins) { + dev_err(cpu_dai->dev, "channel not supported\n"); + return -EINVAL; + } + + bclk = params_rate(params) * (sai->bclk_ratio ? sai->bclk_ratio : slots * slot_width); + + if (!IS_ERR_OR_NULL(sai->pinctrl)) { + sai->pins_state = fsl_sai_get_pins_state(sai, bclk); + if (!IS_ERR_OR_NULL(sai->pins_state)) { + ret = pinctrl_select_state(sai->pinctrl, sai->pins_state); + if (ret) { + dev_err(cpu_dai->dev, "failed to set proper pins state: %d\n", ret); + return ret; + } + } + } + if (!sai->is_consumer_mode) { - if (sai->bclk_ratio) - ret = fsl_sai_set_bclk(cpu_dai, tx, - sai->bclk_ratio * - params_rate(params)); - else - ret = fsl_sai_set_bclk(cpu_dai, tx, - slots * slot_width * - params_rate(params)); + ret = fsl_sai_set_bclk(cpu_dai, tx, bclk); if (ret) return ret; @@ -486,13 +592,13 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, } } - if (!sai->is_dsp_mode) + if (!sai->is_dsp_mode && !sai->is_pdm_mode) val_cr4 |= FSL_SAI_CR4_SYWD(slot_width); val_cr5 |= FSL_SAI_CR5_WNW(slot_width); val_cr5 |= FSL_SAI_CR5_W0W(slot_width); - if (sai->is_lsb_first) + if (sai->is_lsb_first || sai->is_pdm_mode) val_cr5 |= FSL_SAI_CR5_FBT(0); else val_cr5 |= FSL_SAI_CR5_FBT(word_width - 1); @@ -519,13 +625,28 @@ static int fsl_sai_hw_params(struct snd_pcm_substream *substream, FSL_SAI_CR5_FBT_MASK, val_cr5); } - if (sai->soc_data->pins > 1) + if (hweight8(dl_cfg[dl_cfg_idx].mask[tx]) <= 1) + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), + FSL_SAI_CR4_FCOMB_MASK, 0); + else regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_FCOMB_MASK, FSL_SAI_CR4_FCOMB_SOFT); + dma_params = tx ? &sai->dma_params_tx : &sai->dma_params_rx; + dma_params->addr = sai->res->start + FSL_SAI_xDR0(tx) + + dl_cfg[dl_cfg_idx].start_off[tx] * 0x4; + + /* Find a proper tcre setting */ + for (i = 0; i < sai->soc_data->pins; i++) { + trce_mask = (1 << (i + 1)) - 1; + if (hweight8(dl_cfg[dl_cfg_idx].mask[tx] & trce_mask) == pins) + break; + } + regmap_update_bits(sai->regmap, FSL_SAI_xCR3(tx, ofs), FSL_SAI_CR3_TRCE_MASK, - FSL_SAI_CR3_TRCE((1 << pins) - 1)); + FSL_SAI_CR3_TRCE((dl_cfg[dl_cfg_idx].mask[tx] & trce_mask))); + regmap_update_bits(sai->regmap, FSL_SAI_xCR4(tx, ofs), FSL_SAI_CR4_SYWD_MASK | FSL_SAI_CR4_FRSZ_MASK | FSL_SAI_CR4_CHMOD_MASK, @@ -737,6 +858,23 @@ static int fsl_sai_dai_probe(struct snd_soc_dai *cpu_dai) return 0; } +static int fsl_sai_dai_resume(struct snd_soc_component *component) +{ + struct fsl_sai *sai = snd_soc_component_get_drvdata(component); + struct device *dev = &sai->pdev->dev; + int ret; + + if (!IS_ERR_OR_NULL(sai->pinctrl) && !IS_ERR_OR_NULL(sai->pins_state)) { + ret = pinctrl_select_state(sai->pinctrl, sai->pins_state); + if (ret) { + dev_err(dev, "failed to set proper pins state: %d\n", ret); + return ret; + } + } + + return 0; +} + static struct snd_soc_dai_driver fsl_sai_dai_template = { .probe = fsl_sai_dai_probe, .playback = { @@ -744,7 +882,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = { .channels_min = 1, .channels_max = 32, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 2822400, .rates = SNDRV_PCM_RATE_KNOT, .formats = FSL_SAI_FORMATS, }, @@ -753,7 +891,7 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = { .channels_min = 1, .channels_max = 32, .rate_min = 8000, - .rate_max = 192000, + .rate_max = 2822400, .rates = SNDRV_PCM_RATE_KNOT, .formats = FSL_SAI_FORMATS, }, @@ -761,7 +899,9 @@ static struct snd_soc_dai_driver fsl_sai_dai_template = { }; static const struct snd_soc_component_driver fsl_component = { - .name = "fsl-sai", + .name = "fsl-sai", + .resume = fsl_sai_dai_resume, + .legacy_dai_naming = 1, }; static struct reg_default fsl_sai_reg_defaults_ofs0[] = { @@ -998,30 +1138,142 @@ static int fsl_sai_check_version(struct device *dev) return 0; } +/* + * Calculate the offset between first two datalines, don't + * different offset in one case. + */ +static unsigned int fsl_sai_calc_dl_off(unsigned long dl_mask) +{ + int fbidx, nbidx, offset; + + fbidx = find_first_bit(&dl_mask, FSL_SAI_DL_NUM); + nbidx = find_next_bit(&dl_mask, FSL_SAI_DL_NUM, fbidx + 1); + offset = nbidx - fbidx - 1; + + return (offset < 0 || offset >= (FSL_SAI_DL_NUM - 1) ? 0 : offset); +} + +/* + * read the fsl,dataline property from dts file. + * It has 3 value for each configuration, first one means the type: + * I2S(1) or PDM(2), second one is dataline mask for 'rx', third one is + * dataline mask for 'tx'. for example + * + * fsl,dataline = <1 0xff 0xff 2 0xff 0x11>, + * + * It means I2S type rx mask is 0xff, tx mask is 0xff, PDM type + * rx mask is 0xff, tx mask is 0x11 (dataline 1 and 4 enabled). + * + */ +static int fsl_sai_read_dlcfg(struct fsl_sai *sai) +{ + struct platform_device *pdev = sai->pdev; + struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; + int ret, elems, i, index, num_cfg; + char *propname = "fsl,dataline"; + struct fsl_sai_dl_cfg *cfg; + unsigned long dl_mask; + unsigned int soc_dl; + u32 rx, tx, type; + + elems = of_property_count_u32_elems(np, propname); + + if (elems <= 0) { + elems = 0; + } else if (elems % 3) { + dev_err(dev, "Number of elements must be divisible to 3.\n"); + return -EINVAL; + } + + num_cfg = elems / 3; + /* Add one more for default value */ + cfg = devm_kzalloc(&pdev->dev, (num_cfg + 1) * sizeof(*cfg), GFP_KERNEL); + if (!cfg) + return -ENOMEM; + + /* Consider default value "0 0xFF 0xFF" if property is missing */ + soc_dl = BIT(sai->soc_data->pins) - 1; + cfg[0].type = FSL_SAI_DL_DEFAULT; + cfg[0].pins[0] = sai->soc_data->pins; + cfg[0].mask[0] = soc_dl; + cfg[0].start_off[0] = 0; + cfg[0].next_off[0] = 0; + + cfg[0].pins[1] = sai->soc_data->pins; + cfg[0].mask[1] = soc_dl; + cfg[0].start_off[1] = 0; + cfg[0].next_off[1] = 0; + for (i = 1, index = 0; i < num_cfg + 1; i++) { + /* + * type of dataline + * 0 means default mode + * 1 means I2S mode + * 2 means PDM mode + */ + ret = of_property_read_u32_index(np, propname, index++, &type); + if (ret) + return -EINVAL; + + ret = of_property_read_u32_index(np, propname, index++, &rx); + if (ret) + return -EINVAL; + + ret = of_property_read_u32_index(np, propname, index++, &tx); + if (ret) + return -EINVAL; + + if ((rx & ~soc_dl) || (tx & ~soc_dl)) { + dev_err(dev, "dataline cfg[%d] setting error, mask is 0x%x\n", i, soc_dl); + return -EINVAL; + } + + rx = rx & soc_dl; + tx = tx & soc_dl; + + cfg[i].type = type; + cfg[i].pins[0] = hweight8(rx); + cfg[i].mask[0] = rx; + dl_mask = rx; + cfg[i].start_off[0] = find_first_bit(&dl_mask, FSL_SAI_DL_NUM); + cfg[i].next_off[0] = fsl_sai_calc_dl_off(rx); + + cfg[i].pins[1] = hweight8(tx); + cfg[i].mask[1] = tx; + dl_mask = tx; + cfg[i].start_off[1] = find_first_bit(&dl_mask, FSL_SAI_DL_NUM); + cfg[i].next_off[1] = fsl_sai_calc_dl_off(tx); + } + + sai->dl_cfg = cfg; + sai->dl_cfg_cnt = num_cfg + 1; + return 0; +} + static int fsl_sai_runtime_suspend(struct device *dev); static int fsl_sai_runtime_resume(struct device *dev); static int fsl_sai_probe(struct platform_device *pdev) { struct device_node *np = pdev->dev.of_node; + struct device *dev = &pdev->dev; struct fsl_sai *sai; struct regmap *gpr; - struct resource *res; void __iomem *base; char tmp[8]; int irq, ret, i; int index; - sai = devm_kzalloc(&pdev->dev, sizeof(*sai), GFP_KERNEL); + sai = devm_kzalloc(dev, sizeof(*sai), GFP_KERNEL); if (!sai) return -ENOMEM; sai->pdev = pdev; - sai->soc_data = of_device_get_match_data(&pdev->dev); + sai->soc_data = of_device_get_match_data(dev); sai->is_lsb_first = of_property_read_bool(np, "lsb-first"); - base = devm_platform_get_and_ioremap_resource(pdev, 0, &res); + base = devm_platform_get_and_ioremap_resource(pdev, 0, &sai->res); if (IS_ERR(base)) return PTR_ERR(base); @@ -1032,18 +1284,18 @@ static int fsl_sai_probe(struct platform_device *pdev) ARRAY_SIZE(fsl_sai_reg_defaults_ofs8); } - sai->regmap = devm_regmap_init_mmio(&pdev->dev, base, &fsl_sai_regmap_config); + sai->regmap = devm_regmap_init_mmio(dev, base, &fsl_sai_regmap_config); if (IS_ERR(sai->regmap)) { - dev_err(&pdev->dev, "regmap init failed\n"); + dev_err(dev, "regmap init failed\n"); return PTR_ERR(sai->regmap); } - sai->bus_clk = devm_clk_get(&pdev->dev, "bus"); + sai->bus_clk = devm_clk_get(dev, "bus"); /* Compatible with old DTB cases */ if (IS_ERR(sai->bus_clk) && PTR_ERR(sai->bus_clk) != -EPROBE_DEFER) - sai->bus_clk = devm_clk_get(&pdev->dev, "sai"); + sai->bus_clk = devm_clk_get(dev, "sai"); if (IS_ERR(sai->bus_clk)) { - dev_err(&pdev->dev, "failed to get bus clock: %ld\n", + dev_err(dev, "failed to get bus clock: %ld\n", PTR_ERR(sai->bus_clk)); /* -EPROBE_DEFER */ return PTR_ERR(sai->bus_clk); @@ -1051,9 +1303,9 @@ static int fsl_sai_probe(struct platform_device *pdev) for (i = 1; i < FSL_SAI_MCLK_MAX; i++) { sprintf(tmp, "mclk%d", i); - sai->mclk_clk[i] = devm_clk_get(&pdev->dev, tmp); + sai->mclk_clk[i] = devm_clk_get(dev, tmp); if (IS_ERR(sai->mclk_clk[i])) { - dev_err(&pdev->dev, "failed to get mclk%d clock: %ld\n", + dev_err(dev, "failed to get mclk%d clock: %ld\n", i + 1, PTR_ERR(sai->mclk_clk[i])); sai->mclk_clk[i] = NULL; } @@ -1064,14 +1316,24 @@ static int fsl_sai_probe(struct platform_device *pdev) else sai->mclk_clk[0] = sai->bus_clk; + fsl_asoc_get_pll_clocks(&pdev->dev, &sai->pll8k_clk, + &sai->pll11k_clk); + + /* read dataline mask for rx and tx*/ + ret = fsl_sai_read_dlcfg(sai); + if (ret < 0) { + dev_err(dev, "failed to read dlcfg %d\n", ret); + return ret; + } + irq = platform_get_irq(pdev, 0); if (irq < 0) return irq; - ret = devm_request_irq(&pdev->dev, irq, fsl_sai_isr, IRQF_SHARED, + ret = devm_request_irq(dev, irq, fsl_sai_isr, IRQF_SHARED, np->name, sai); if (ret) { - dev_err(&pdev->dev, "failed to claim irq %u\n", irq); + dev_err(dev, "failed to claim irq %u\n", irq); return ret; } @@ -1088,7 +1350,7 @@ static int fsl_sai_probe(struct platform_device *pdev) if (of_find_property(np, "fsl,sai-synchronous-rx", NULL) && of_find_property(np, "fsl,sai-asynchronous", NULL)) { /* error out if both synchronous and asynchronous are present */ - dev_err(&pdev->dev, "invalid binding for synchronous mode\n"); + dev_err(dev, "invalid binding for synchronous mode\n"); return -EINVAL; } @@ -1109,7 +1371,7 @@ static int fsl_sai_probe(struct platform_device *pdev) of_device_is_compatible(np, "fsl,imx6ul-sai")) { gpr = syscon_regmap_lookup_by_compatible("fsl,imx6ul-iomuxc-gpr"); if (IS_ERR(gpr)) { - dev_err(&pdev->dev, "cannot find iomuxc registers\n"); + dev_err(dev, "cannot find iomuxc registers\n"); return PTR_ERR(gpr); } @@ -1121,29 +1383,29 @@ static int fsl_sai_probe(struct platform_device *pdev) MCLK_DIR(index)); } - sai->dma_params_rx.addr = res->start + FSL_SAI_RDR0; - sai->dma_params_tx.addr = res->start + FSL_SAI_TDR0; + sai->dma_params_rx.addr = sai->res->start + FSL_SAI_RDR0; + sai->dma_params_tx.addr = sai->res->start + FSL_SAI_TDR0; sai->dma_params_rx.maxburst = FSL_SAI_MAXBURST_RX; sai->dma_params_tx.maxburst = FSL_SAI_MAXBURST_TX; + sai->pinctrl = devm_pinctrl_get(&pdev->dev); + platform_set_drvdata(pdev, sai); - pm_runtime_enable(&pdev->dev); - if (!pm_runtime_enabled(&pdev->dev)) { - ret = fsl_sai_runtime_resume(&pdev->dev); + pm_runtime_enable(dev); + if (!pm_runtime_enabled(dev)) { + ret = fsl_sai_runtime_resume(dev); if (ret) goto err_pm_disable; } - ret = pm_runtime_get_sync(&pdev->dev); - if (ret < 0) { - pm_runtime_put_noidle(&pdev->dev); + ret = pm_runtime_resume_and_get(dev); + if (ret < 0) goto err_pm_get_sync; - } /* Get sai version */ - ret = fsl_sai_check_version(&pdev->dev); + ret = fsl_sai_check_version(dev); if (ret < 0) - dev_warn(&pdev->dev, "Error reading SAI version: %d\n", ret); + dev_warn(dev, "Error reading SAI version: %d\n", ret); /* Select MCLK direction */ if (of_find_property(np, "fsl,sai-mclk-direction-output", NULL) && @@ -1152,7 +1414,7 @@ static int fsl_sai_probe(struct platform_device *pdev) FSL_SAI_MCTL_MCLK_EN, FSL_SAI_MCTL_MCLK_EN); } - ret = pm_runtime_put_sync(&pdev->dev); + ret = pm_runtime_put_sync(dev); if (ret < 0) goto err_pm_get_sync; @@ -1162,15 +1424,18 @@ static int fsl_sai_probe(struct platform_device *pdev) */ if (sai->soc_data->use_imx_pcm) { ret = imx_pcm_dma_init(pdev); - if (ret) + if (ret) { + if (!IS_ENABLED(CONFIG_SND_SOC_IMX_PCM_DMA)) + dev_err(dev, "Error: You must enable the imx-pcm-dma support!\n"); goto err_pm_get_sync; + } } else { - ret = devm_snd_dmaengine_pcm_register(&pdev->dev, NULL, 0); + ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0); if (ret) goto err_pm_get_sync; } - ret = devm_snd_soc_register_component(&pdev->dev, &fsl_component, + ret = devm_snd_soc_register_component(dev, &fsl_component, &sai->cpu_dai_drv, 1); if (ret) goto err_pm_get_sync; @@ -1178,10 +1443,10 @@ static int fsl_sai_probe(struct platform_device *pdev) return ret; err_pm_get_sync: - if (!pm_runtime_status_suspended(&pdev->dev)) - fsl_sai_runtime_suspend(&pdev->dev); + if (!pm_runtime_status_suspended(dev)) + fsl_sai_runtime_suspend(dev); err_pm_disable: - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); return ret; } @@ -1293,6 +1558,7 @@ static const struct of_device_id fsl_sai_ids[] = { { .compatible = "fsl,imx8mm-sai", .data = &fsl_sai_imx8mm_data }, { .compatible = "fsl,imx8mp-sai", .data = &fsl_sai_imx8mp_data }, { .compatible = "fsl,imx8ulp-sai", .data = &fsl_sai_imx8ulp_data }, + { .compatible = "fsl,imx8mn-sai", .data = &fsl_sai_imx8mp_data }, { /* sentinel */ } }; MODULE_DEVICE_TABLE(of, fsl_sai_ids); diff --git a/sound/soc/fsl/fsl_sai.h b/sound/soc/fsl/fsl_sai.h index 1c8f5ca07f9d..17956b5731dc 100644 --- a/sound/soc/fsl/fsl_sai.h +++ b/sound/soc/fsl/fsl_sai.h @@ -11,7 +11,10 @@ #define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\ SNDRV_PCM_FMTBIT_S20_3LE |\ SNDRV_PCM_FMTBIT_S24_LE |\ - SNDRV_PCM_FMTBIT_S32_LE) + SNDRV_PCM_FMTBIT_S32_LE |\ + SNDRV_PCM_FMTBIT_DSD_U8 |\ + SNDRV_PCM_FMTBIT_DSD_U16_LE |\ + SNDRV_PCM_FMTBIT_DSD_U32_LE) /* SAI Register Map Register */ #define FSL_SAI_VERID 0x00 /* SAI Version ID Register */ @@ -215,6 +218,13 @@ #define PMQOS_CPU_LATENCY BIT(0) +/* Max number of dataline */ +#define FSL_SAI_DL_NUM (8) +/* default dataline type is zero */ +#define FSL_SAI_DL_DEFAULT (0) +#define FSL_SAI_DL_I2S BIT(0) +#define FSL_SAI_DL_PDM BIT(1) + struct fsl_sai_soc_data { bool use_imx_pcm; bool use_edma; @@ -250,16 +260,30 @@ struct fsl_sai_param { u32 dataline; }; +struct fsl_sai_dl_cfg { + unsigned int type; + unsigned int pins[2]; + unsigned int mask[2]; + unsigned int start_off[2]; + unsigned int next_off[2]; +}; + struct fsl_sai { struct platform_device *pdev; struct regmap *regmap; struct clk *bus_clk; struct clk *mclk_clk[FSL_SAI_MCLK_MAX]; + struct clk *pll8k_clk; + struct clk *pll11k_clk; + struct resource *res; bool is_consumer_mode; bool is_lsb_first; bool is_dsp_mode; + bool is_pdm_mode; bool synchronous[2]; + struct fsl_sai_dl_cfg *dl_cfg; + unsigned int dl_cfg_cnt; unsigned int mclk_id[2]; unsigned int mclk_streams; @@ -274,6 +298,8 @@ struct fsl_sai { struct fsl_sai_verid verid; struct fsl_sai_param param; struct pm_qos_request pm_qos_req; + struct pinctrl *pinctrl; + struct pinctrl_state *pins_state; }; #define TX 1 diff --git a/sound/soc/fsl/fsl_spdif.c b/sound/soc/fsl/fsl_spdif.c index 42d11aca38a1..7fc1c96929bb 100644 --- a/sound/soc/fsl/fsl_spdif.c +++ b/sound/soc/fsl/fsl_spdif.c @@ -23,6 +23,7 @@ #include <sound/soc.h> #include "fsl_spdif.h" +#include "fsl_utils.h" #include "imx-pcm.h" #define FSL_SPDIF_TXFIFO_WML 0x8 @@ -114,6 +115,8 @@ struct spdif_mixer_control { * @dma_params_rx: DMA parameters for receive channel * @regcache_srpc: regcache for SRPC * @bypass: status of bypass input to output + * @pll8k_clk: PLL clock for the rate of multiply of 8kHz + * @pll11k_clk: PLL clock for the rate of multiply of 11kHz */ struct fsl_spdif_priv { const struct fsl_spdif_soc_data *soc; @@ -137,6 +140,8 @@ struct fsl_spdif_priv { /* regcache for SRPC */ u32 regcache_srpc; bool bypass; + struct clk *pll8k_clk; + struct clk *pll11k_clk; }; static struct fsl_spdif_soc_data fsl_spdif_vf610 = { @@ -480,6 +485,8 @@ static int spdif_set_rx_clksrc(struct fsl_spdif_priv *spdif_priv, return 0; } +static int fsl_spdif_probe_txclk(struct fsl_spdif_priv *spdif_priv, enum spdif_txrate index); + static int spdif_set_sample_rate(struct snd_pcm_substream *substream, int sample_rate) { @@ -528,6 +535,10 @@ static int spdif_set_sample_rate(struct snd_pcm_substream *substream, return -EINVAL; } + ret = fsl_spdif_probe_txclk(spdif_priv, rate); + if (ret) + return ret; + clk = spdif_priv->txclk_src[rate]; if (clk >= STC_TXCLK_SRC_MAX) { dev_err(&pdev->dev, "tx clock source is out of range\n"); @@ -647,6 +658,29 @@ static void fsl_spdif_shutdown(struct snd_pcm_substream *substream, } } +static int spdif_reparent_rootclk(struct fsl_spdif_priv *spdif_priv, unsigned int sample_rate) +{ + struct platform_device *pdev = spdif_priv->pdev; + struct clk *clk; + int ret; + + /* Reparent clock if required condition is true */ + if (!fsl_spdif_can_set_clk_rate(spdif_priv, STC_TXCLK_SPDIF_ROOT)) + return 0; + + /* Get root clock */ + clk = spdif_priv->txclk[STC_TXCLK_SPDIF_ROOT]; + + /* Disable clock first, for it was enabled by pm_runtime */ + clk_disable_unprepare(clk); + fsl_asoc_reparent_pll_clocks(&pdev->dev, clk, spdif_priv->pll8k_clk, + spdif_priv->pll11k_clk, sample_rate); + ret = clk_prepare_enable(clk); + if (ret) + return ret; + + return 0; +} static int fsl_spdif_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params, struct snd_soc_dai *dai) @@ -659,6 +693,13 @@ static int fsl_spdif_hw_params(struct snd_pcm_substream *substream, int ret = 0; if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { + ret = spdif_reparent_rootclk(spdif_priv, sample_rate); + if (ret) { + dev_err(&pdev->dev, "%s: reparent root clk failed: %d\n", + __func__, sample_rate); + return ret; + } + ret = spdif_set_sample_rate(substream, sample_rate); if (ret) { dev_err(&pdev->dev, "%s: set sample rate failed: %d\n", @@ -1237,7 +1278,8 @@ static struct snd_soc_dai_driver fsl_spdif_dai = { }; static const struct snd_soc_component_driver fsl_spdif_component = { - .name = "fsl-spdif", + .name = "fsl-spdif", + .legacy_dai_naming = 1, }; /* FSL SPDIF REGMAP */ @@ -1547,11 +1589,8 @@ static int fsl_spdif_probe(struct platform_device *pdev) } spdif_priv->rxclk_src = DEFAULT_RXCLK_SRC; - for (i = 0; i < SPDIF_TXRATE_MAX; i++) { - ret = fsl_spdif_probe_txclk(spdif_priv, i); - if (ret) - return ret; - } + fsl_asoc_get_pll_clocks(&pdev->dev, &spdif_priv->pll8k_clk, + &spdif_priv->pll11k_clk); /* Initial spinlock for control data */ ctrl = &spdif_priv->fsl_spdif_control; diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c index 84cb36d9dfea..c9e0e31d5b34 100644 --- a/sound/soc/fsl/fsl_ssi.c +++ b/sound/soc/fsl/fsl_ssi.c @@ -93,7 +93,7 @@ */ #define FSLSSI_AC97_DAIFMT \ (SND_SOC_DAIFMT_AC97 | \ - SND_SOC_DAIFMT_CBM_CFS | \ + SND_SOC_DAIFMT_BC_FP | \ SND_SOC_DAIFMT_NB_NF) #define FSLSSI_SIER_DBG_RX_FLAGS \ @@ -358,13 +358,13 @@ static bool fsl_ssi_is_ac97(struct fsl_ssi *ssi) static bool fsl_ssi_is_i2s_clock_provider(struct fsl_ssi *ssi) { return (ssi->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == - SND_SOC_DAIFMT_CBC_CFC; + SND_SOC_DAIFMT_BP_FP; } -static bool fsl_ssi_is_i2s_cbp_cfc(struct fsl_ssi *ssi) +static bool fsl_ssi_is_i2s_bc_fp(struct fsl_ssi *ssi) { return (ssi->dai_fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) == - SND_SOC_DAIFMT_CBP_CFC; + SND_SOC_DAIFMT_BC_FP; } /** @@ -847,7 +847,7 @@ static int fsl_ssi_hw_params(struct snd_pcm_substream *substream, u8 i2s_net = ssi->i2s_net; /* Normal + Network mode to send 16-bit data in 32-bit frames */ - if (fsl_ssi_is_i2s_cbp_cfc(ssi) && sample_size == 16) + if (fsl_ssi_is_i2s_bc_fp(ssi) && sample_size == 16) i2s_net = SSI_SCR_I2S_MODE_NORMAL | SSI_SCR_NET; /* Use Normal mode to send mono data at 1st slot of 2 slots */ @@ -920,17 +920,17 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt) switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: if (IS_ERR(ssi->baudclk)) { dev_err(ssi->dev, "missing baudclk for master mode\n"); return -EINVAL; } fallthrough; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: ssi->i2s_net |= SSI_SCR_I2S_MODE_MASTER; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: ssi->i2s_net |= SSI_SCR_I2S_MODE_SLAVE; break; default: @@ -992,15 +992,15 @@ static int _fsl_ssi_set_dai_fmt(struct fsl_ssi *ssi, unsigned int fmt) /* DAI clock provider masks */ switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { - case SND_SOC_DAIFMT_CBC_CFC: + case SND_SOC_DAIFMT_BP_FP: /* Output bit and frame sync clocks */ strcr |= SSI_STCR_TFDIR | SSI_STCR_TXDIR; scr |= SSI_SCR_SYS_CLK_EN; break; - case SND_SOC_DAIFMT_CBP_CFP: + case SND_SOC_DAIFMT_BC_FC: /* Input bit or frame sync clocks */ break; - case SND_SOC_DAIFMT_CBP_CFC: + case SND_SOC_DAIFMT_BC_FP: /* Input bit clock but output frame sync clock */ strcr |= SSI_STCR_TFDIR; break; @@ -1182,6 +1182,7 @@ static struct snd_soc_dai_driver fsl_ssi_dai_template = { static const struct snd_soc_component_driver fsl_ssi_component = { .name = "fsl-ssi", + .legacy_dai_naming = 1, }; static struct snd_soc_dai_driver fsl_ssi_ac97_dai = { diff --git a/sound/soc/fsl/fsl_utils.c b/sound/soc/fsl/fsl_utils.c index 9bab202569af..d0fc430f7033 100644 --- a/sound/soc/fsl/fsl_utils.c +++ b/sound/soc/fsl/fsl_utils.c @@ -6,6 +6,8 @@ // // Copyright 2010 Freescale Semiconductor, Inc. +#include <linux/clk.h> +#include <linux/clk-provider.h> #include <linux/module.h> #include <linux/of_address.h> #include <sound/soc.h> @@ -83,6 +85,73 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, } EXPORT_SYMBOL(fsl_asoc_get_dma_channel); +/** + * fsl_asoc_get_pll_clocks - get two PLL clock source + * + * @dev: device pointer + * @pll8k_clk: PLL clock pointer for 8kHz + * @pll11k_clk: PLL clock pointer for 11kHz + * + * This function get two PLL clock source + */ +void fsl_asoc_get_pll_clocks(struct device *dev, struct clk **pll8k_clk, + struct clk **pll11k_clk) +{ + *pll8k_clk = devm_clk_get(dev, "pll8k"); + if (IS_ERR(*pll8k_clk)) + *pll8k_clk = NULL; + + *pll11k_clk = devm_clk_get(dev, "pll11k"); + if (IS_ERR(*pll11k_clk)) + *pll11k_clk = NULL; +} +EXPORT_SYMBOL(fsl_asoc_get_pll_clocks); + +/** + * fsl_asoc_reparent_pll_clocks - set clock parent if necessary + * + * @dev: device pointer + * @clk: root clock pointer + * @pll8k_clk: PLL clock pointer for 8kHz + * @pll11k_clk: PLL clock pointer for 11kHz + * @ratio: target requency for root clock + * + * This function set root clock parent according to the target ratio + */ +void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk, + struct clk *pll8k_clk, + struct clk *pll11k_clk, u64 ratio) +{ + struct clk *p, *pll = NULL, *npll = NULL; + bool reparent = false; + int ret = 0; + + if (!clk || !pll8k_clk || !pll11k_clk) + return; + + p = clk; + while (p && pll8k_clk && pll11k_clk) { + struct clk *pp = clk_get_parent(p); + + if (clk_is_match(pp, pll8k_clk) || + clk_is_match(pp, pll11k_clk)) { + pll = pp; + break; + } + p = pp; + } + + npll = (do_div(ratio, 8000) ? pll11k_clk : pll8k_clk); + reparent = (pll && !clk_is_match(pll, npll)); + + if (reparent) { + ret = clk_set_parent(p, npll); + if (ret < 0) + dev_warn(dev, "failed to set parent:%d\n", ret); + } +} +EXPORT_SYMBOL(fsl_asoc_reparent_pll_clocks); + MODULE_AUTHOR("Timur Tabi <timur@freescale.com>"); MODULE_DESCRIPTION("Freescale ASoC utility code"); MODULE_LICENSE("GPL v2"); diff --git a/sound/soc/fsl/fsl_utils.h b/sound/soc/fsl/fsl_utils.h index c5dc2a14b492..4d5f3d93bc81 100644 --- a/sound/soc/fsl/fsl_utils.h +++ b/sound/soc/fsl/fsl_utils.h @@ -19,4 +19,11 @@ int fsl_asoc_get_dma_channel(struct device_node *ssi_np, const char *name, struct snd_soc_dai_link *dai, unsigned int *dma_channel_id, unsigned int *dma_id); + +void fsl_asoc_get_pll_clocks(struct device *dev, struct clk **pll8k_clk, + struct clk **pll11k_clk); + +void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk, + struct clk *pll8k_clk, + struct clk *pll11k_clk, u64 ratio); #endif /* _FSL_UTILS_H */ diff --git a/sound/soc/fsl/fsl_xcvr.c b/sound/soc/fsl/fsl_xcvr.c index d0556c79fdb1..c043efe4548d 100644 --- a/sound/soc/fsl/fsl_xcvr.c +++ b/sound/soc/fsl/fsl_xcvr.c @@ -911,7 +911,8 @@ static struct snd_soc_dai_driver fsl_xcvr_dai = { }; static const struct snd_soc_component_driver fsl_xcvr_comp = { - .name = "fsl-xcvr-dai", + .name = "fsl-xcvr-dai", + .legacy_dai_naming = 1, }; static const struct reg_default fsl_xcvr_reg_defaults[] = { @@ -1228,6 +1229,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev) */ ret = devm_snd_dmaengine_pcm_register(dev, NULL, 0); if (ret) { + pm_runtime_disable(dev); dev_err(dev, "failed to pcm register\n"); return ret; } @@ -1235,6 +1237,7 @@ static int fsl_xcvr_probe(struct platform_device *pdev) ret = devm_snd_soc_register_component(dev, &fsl_xcvr_comp, &fsl_xcvr_dai, 1); if (ret) { + pm_runtime_disable(dev); dev_err(dev, "failed to register component %s\n", fsl_xcvr_comp.name); } @@ -1242,6 +1245,12 @@ static int fsl_xcvr_probe(struct platform_device *pdev) return ret; } +static int fsl_xcvr_remove(struct platform_device *pdev) +{ + pm_runtime_disable(&pdev->dev); + return 0; +} + static __maybe_unused int fsl_xcvr_runtime_suspend(struct device *dev) { struct fsl_xcvr *xcvr = dev_get_drvdata(dev); @@ -1370,6 +1379,7 @@ static struct platform_driver fsl_xcvr_driver = { .pm = &fsl_xcvr_pm_ops, .of_match_table = fsl_xcvr_dt_ids, }, + .remove = fsl_xcvr_remove, }; module_platform_driver(fsl_xcvr_driver); diff --git a/sound/soc/fsl/imx-audmix.c b/sound/soc/fsl/imx-audmix.c index 502fe1b522ab..1292a845c424 100644 --- a/sound/soc/fsl/imx-audmix.c +++ b/sound/soc/fsl/imx-audmix.c @@ -81,7 +81,7 @@ static int imx_audmix_fe_hw_params(struct snd_pcm_substream *substream, int ret, dir; /* For playback the AUDMIX is consumer, and for record is provider */ - fmt |= tx ? SND_SOC_DAIFMT_CBC_CFC : SND_SOC_DAIFMT_CBP_CFP; + fmt |= tx ? SND_SOC_DAIFMT_BP_FP : SND_SOC_DAIFMT_BC_FC; dir = tx ? SND_SOC_CLOCK_OUT : SND_SOC_CLOCK_IN; /* set DAI configuration */ @@ -122,7 +122,7 @@ static int imx_audmix_be_hw_params(struct snd_pcm_substream *substream, return 0; /* For playback the AUDMIX is consumer */ - fmt |= SND_SOC_DAIFMT_CBP_CFP; + fmt |= SND_SOC_DAIFMT_BC_FC; /* set AUDMIX DAI configuration */ ret = snd_soc_dai_set_fmt(asoc_rtd_to_cpu(rtd, 0), fmt); diff --git a/sound/soc/fsl/imx-audmux.c b/sound/soc/fsl/imx-audmux.c index dfa05d40b276..50b71e5d4589 100644 --- a/sound/soc/fsl/imx-audmux.c +++ b/sound/soc/fsl/imx-audmux.c @@ -62,17 +62,14 @@ static ssize_t audmux_read_file(struct file *file, char __user *user_buf, uintptr_t port = (uintptr_t)file->private_data; u32 pdcr, ptcr; - if (audmux_clk) { - ret = clk_prepare_enable(audmux_clk); - if (ret) - return ret; - } + ret = clk_prepare_enable(audmux_clk); + if (ret) + return ret; ptcr = readl(audmux_base + IMX_AUDMUX_V2_PTCR(port)); pdcr = readl(audmux_base + IMX_AUDMUX_V2_PDCR(port)); - if (audmux_clk) - clk_disable_unprepare(audmux_clk); + clk_disable_unprepare(audmux_clk); buf = kmalloc(PAGE_SIZE, GFP_KERNEL); if (!buf) @@ -209,17 +206,14 @@ int imx_audmux_v2_configure_port(unsigned int port, unsigned int ptcr, if (!audmux_base) return -ENOSYS; - if (audmux_clk) { - ret = clk_prepare_enable(audmux_clk); - if (ret) - return ret; - } + ret = clk_prepare_enable(audmux_clk); + if (ret) + return ret; writel(ptcr, audmux_base + IMX_AUDMUX_V2_PTCR(port)); writel(pdcr, audmux_base + IMX_AUDMUX_V2_PDCR(port)); - if (audmux_clk) - clk_disable_unprepare(audmux_clk); + clk_disable_unprepare(audmux_clk); return 0; } @@ -298,7 +292,7 @@ static int imx_audmux_probe(struct platform_device *pdev) audmux_clk = NULL; } - audmux_type = (enum imx_audmux_type)of_device_get_match_data(&pdev->dev); + audmux_type = (uintptr_t)of_device_get_match_data(&pdev->dev); switch (audmux_type) { case IMX31_AUDMUX: diff --git a/sound/soc/fsl/imx-card.c b/sound/soc/fsl/imx-card.c index 6f8efd838fcc..14be29530fb5 100644 --- a/sound/soc/fsl/imx-card.c +++ b/sound/soc/fsl/imx-card.c @@ -17,6 +17,9 @@ #include "fsl_sai.h" +#define IMX_CARD_MCLK_22P5792MHZ 22579200 +#define IMX_CARD_MCLK_24P576MHZ 24576000 + enum codec_type { CODEC_DUMMY = 0, CODEC_AK5558 = 1, @@ -115,7 +118,7 @@ struct imx_card_data { struct snd_soc_card card; int num_dapm_routes; u32 asrc_rate; - u32 asrc_format; + snd_pcm_format_t asrc_format; }; static struct imx_akcodec_fs_mul ak4458_fs_mul[] = { @@ -317,7 +320,7 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, } } - ret = snd_soc_dai_set_fmt(cpu_dai, fmt); + ret = snd_soc_dai_set_fmt(cpu_dai, snd_soc_daifmt_clock_provider_flipped(fmt)); if (ret && ret != -ENOTSUPP) { dev_err(dev, "failed to set cpu dai fmt: %d\n", ret); return ret; @@ -353,9 +356,14 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream, mclk_freq = akcodec_get_mclk_rate(substream, params, slots, slot_width); else mclk_freq = params_rate(params) * slots * slot_width; - /* Use the maximum freq from DSD512 (512*44100 = 22579200) */ - if (format_is_dsd(params)) - mclk_freq = 22579200; + + if (format_is_dsd(params)) { + /* Use the maximum freq from DSD512 (512*44100 = 22579200) */ + if (!(params_rate(params) % 11025)) + mclk_freq = IMX_CARD_MCLK_22P5792MHZ; + else + mclk_freq = IMX_CARD_MCLK_24P576MHZ; + } ret = snd_soc_dai_set_sysclk(cpu_dai, link_data->cpu_sysclk_id, mclk_freq, SND_SOC_CLOCK_OUT); @@ -466,7 +474,7 @@ static int be_hw_params_fixup(struct snd_soc_pcm_runtime *rtd, mask = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); snd_mask_none(mask); - snd_mask_set(mask, data->asrc_format); + snd_mask_set(mask, (__force unsigned int)data->asrc_format); return 0; } @@ -485,6 +493,7 @@ static int imx_card_parse_of(struct imx_card_data *data) struct dai_link_data *link_data; struct of_phandle_args args; int ret, num_links; + u32 asrc_fmt = 0; u32 width; ret = snd_soc_of_parse_card_name(card, "model"); @@ -631,7 +640,8 @@ static int imx_card_parse_of(struct imx_card_data *data) goto err; } - ret = of_property_read_u32(args.np, "fsl,asrc-format", &data->asrc_format); + ret = of_property_read_u32(args.np, "fsl,asrc-format", &asrc_fmt); + data->asrc_format = (__force snd_pcm_format_t)asrc_fmt; if (ret) { /* Fallback to old binding; translate to asrc_format */ ret = of_property_read_u32(args.np, "fsl,asrc-width", &width); diff --git a/sound/soc/fsl/mpc5200_psc_i2s.c b/sound/soc/fsl/mpc5200_psc_i2s.c index 3149d59ae968..73f3e61f208a 100644 --- a/sound/soc/fsl/mpc5200_psc_i2s.c +++ b/sound/soc/fsl/mpc5200_psc_i2s.c @@ -148,7 +148,8 @@ static struct snd_soc_dai_driver psc_i2s_dai[] = {{ } }; static const struct snd_soc_component_driver psc_i2s_component = { - .name = "mpc5200-i2s", + .name = "mpc5200-i2s", + .legacy_dai_naming = 1, }; /* --------------------------------------------------------------------- diff --git a/sound/soc/fsl/pcm030-audio-fabric.c b/sound/soc/fsl/pcm030-audio-fabric.c index 83b4a22bf15a..997c3e66c636 100644 --- a/sound/soc/fsl/pcm030-audio-fabric.c +++ b/sound/soc/fsl/pcm030-audio-fabric.c @@ -101,8 +101,7 @@ static int pcm030_fabric_probe(struct platform_device *op) ret = snd_soc_register_card(card); if (ret) { dev_err(&op->dev, "snd_soc_register_card() failed: %d\n", ret); - platform_device_del(pdata->codec_device); - platform_device_put(pdata->codec_device); + platform_device_unregister(pdata->codec_device); } platform_set_drvdata(op, pdata); @@ -113,12 +112,11 @@ static int pcm030_fabric_probe(struct platform_device *op) static int pcm030_fabric_remove(struct platform_device *op) { struct pcm030_audio_data *pdata = platform_get_drvdata(op); - int ret; - ret = snd_soc_unregister_card(pdata->card); + snd_soc_unregister_card(pdata->card); platform_device_unregister(pdata->codec_device); - return ret; + return 0; } static const struct of_device_id pcm030_audio_match[] = { |