Unverified Commit 527acf5d authored by Mark Brown's avatar Mark Brown
Browse files

Add function to constrain rates

Merge series from Chancel Liu <chancel.liu@nxp.com>:

Platforms like i.MX93/91 only have one audio PLL. Some sample rates are
not supported. If the PLL source is used for 8kHz series rates, then
11kHz series rates can't be supported. Add common function to constrain
rates according to different clock sources.

In ASoC drivers switch to this new function.
parents 5a305d9d 4edc9859
Loading
Loading
Loading
Loading
+16 −17
Original line number Diff line number Diff line
@@ -35,6 +35,15 @@
#define MICFIL_AUDIO_PLL2	1
#define MICFIL_CLK_EXT3		2

static const unsigned int fsl_micfil_rates[] = {
	8000, 11025, 16000, 22050, 32000, 44100, 48000,
};

static const struct snd_pcm_hw_constraint_list fsl_micfil_rate_constraints = {
	.count = ARRAY_SIZE(fsl_micfil_rates),
	.list = fsl_micfil_rates,
};

enum quality {
	QUALITY_HIGH,
	QUALITY_MEDIUM,
@@ -486,29 +495,12 @@ static int fsl_micfil_startup(struct snd_pcm_substream *substream,
			      struct snd_soc_dai *dai)
{
	struct fsl_micfil *micfil = snd_soc_dai_get_drvdata(dai);
	unsigned int rates[MICFIL_NUM_RATES] = {8000, 11025, 16000, 22050, 32000, 44100, 48000};
	int i, j, k = 0;
	u64 clk_rate;

	if (!micfil) {
		dev_err(dai->dev, "micfil dai priv_data not set\n");
		return -EINVAL;
	}

	micfil->constraint_rates.list = micfil->constraint_rates_list;
	micfil->constraint_rates.count = 0;

	for (j = 0; j < MICFIL_NUM_RATES; j++) {
		for (i = 0; i < MICFIL_CLK_SRC_NUM; i++) {
			clk_rate = clk_get_rate(micfil->clk_src[i]);
			if (clk_rate != 0 && do_div(clk_rate, rates[j]) == 0) {
				micfil->constraint_rates_list[k++] = rates[j];
				micfil->constraint_rates.count++;
				break;
			}
		}
	}

	if (micfil->constraint_rates.count > 0)
		snd_pcm_hw_constraint_list(substream->runtime, 0,
					   SNDRV_PCM_HW_PARAM_RATE,
@@ -1239,6 +1231,13 @@ static int fsl_micfil_probe(struct platform_device *pdev)
	if (IS_ERR(micfil->clk_src[MICFIL_CLK_EXT3]))
		micfil->clk_src[MICFIL_CLK_EXT3] = NULL;

	fsl_asoc_constrain_rates(&micfil->constraint_rates,
				 &fsl_micfil_rate_constraints,
				 micfil->clk_src[MICFIL_AUDIO_PLL1],
				 micfil->clk_src[MICFIL_AUDIO_PLL2],
				 micfil->clk_src[MICFIL_CLK_EXT3],
				 micfil->constraint_rates_list);

	/* init regmap */
	regs = devm_platform_get_and_ioremap_resource(pdev, 0, &res);
	if (IS_ERR(regs))
+6 −1
Original line number Diff line number Diff line
@@ -885,7 +885,7 @@ static int fsl_sai_startup(struct snd_pcm_substream *substream,
					   sai->dma_params_rx.maxburst);

	ret = snd_pcm_hw_constraint_list(substream->runtime, 0,
			SNDRV_PCM_HW_PARAM_RATE, &fsl_sai_rate_constraints);
					 SNDRV_PCM_HW_PARAM_RATE, &sai->constraint_rates);

	return ret;
}
@@ -1442,6 +1442,11 @@ static int fsl_sai_probe(struct platform_device *pdev)
	fsl_asoc_get_pll_clocks(&pdev->dev, &sai->pll8k_clk,
				&sai->pll11k_clk);

	fsl_asoc_constrain_rates(&sai->constraint_rates,
				 &fsl_sai_rate_constraints,
				 sai->pll8k_clk, sai->pll11k_clk, NULL,
				 sai->constraint_rates_list);

	/* Use Multi FIFO mode depending on the support from SDMA script */
	ret = of_property_read_u32_array(np, "dmas", dmas, 4);
	if (!sai->soc_data->use_edma && !ret && dmas[2] == IMX_DMATYPE_MULTI_SAI)
+3 −0
Original line number Diff line number Diff line
@@ -9,6 +9,7 @@
#include <linux/dma/imx-dma.h>
#include <sound/dmaengine_pcm.h>

#define FAL_SAI_NUM_RATES  20
#define FSL_SAI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE |\
			 SNDRV_PCM_FMTBIT_S20_3LE |\
			 SNDRV_PCM_FMTBIT_S24_LE |\
@@ -309,6 +310,8 @@ struct fsl_sai {
	struct pinctrl *pinctrl;
	struct pinctrl_state *pins_state;
	struct sdma_peripheral_config audio_config[2];
	struct snd_pcm_hw_constraint_list constraint_rates;
	unsigned int constraint_rates_list[FAL_SAI_NUM_RATES];
};

#define TX 1
+45 −0
Original line number Diff line number Diff line
@@ -152,6 +152,51 @@ void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk,
}
EXPORT_SYMBOL(fsl_asoc_reparent_pll_clocks);

/**
 * fsl_asoc_constrain_rates - constrain rates according to clocks
 *
 * @target_constr: target constraint
 * @original_constr: original constraint
 * @pll8k_clk: PLL clock pointer for 8kHz
 * @pll11k_clk: PLL clock pointer for 11kHz
 * @ext_clk: External clock pointer
 * @target_rates: target rates array
 *
 * This function constrain rates according to clocks
 */
void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
			      const struct snd_pcm_hw_constraint_list *original_constr,
			      struct clk *pll8k_clk, struct clk *pll11k_clk,
			      struct clk *ext_clk, int *target_rates)
{
	int i, j, k = 0;
	u64 clk_rate[3];

	*target_constr = *original_constr;
	if (pll8k_clk || pll11k_clk || ext_clk) {
		target_constr->list = target_rates;
		target_constr->count = 0;
		for (i = 0; i < original_constr->count; i++) {
			clk_rate[0] = clk_get_rate(pll8k_clk);
			clk_rate[1] = clk_get_rate(pll11k_clk);
			clk_rate[2] = clk_get_rate(ext_clk);
			for (j = 0; j < 3; j++) {
				if (clk_rate[j] != 0 &&
				    do_div(clk_rate[j], original_constr->list[i]) == 0) {
					target_rates[k++] = original_constr->list[i];
					target_constr->count++;
					break;
				}
			}
		}

		/* protection for if there is no proper rate found*/
		if (!target_constr->count)
			*target_constr = *original_constr;
	}
}
EXPORT_SYMBOL(fsl_asoc_constrain_rates);

MODULE_AUTHOR("Timur Tabi <timur@freescale.com>");
MODULE_DESCRIPTION("Freescale ASoC utility code");
MODULE_LICENSE("GPL v2");
+5 −0
Original line number Diff line number Diff line
@@ -26,4 +26,9 @@ void fsl_asoc_get_pll_clocks(struct device *dev, struct clk **pll8k_clk,
void fsl_asoc_reparent_pll_clocks(struct device *dev, struct clk *clk,
				  struct clk *pll8k_clk,
				  struct clk *pll11k_clk, u64 ratio);

void fsl_asoc_constrain_rates(struct snd_pcm_hw_constraint_list *target_constr,
			      const struct snd_pcm_hw_constraint_list *original_constr,
			      struct clk *pll8k_clk, struct clk *pll11k_clk,
			      struct clk *ext_clk, int *target_rates);
#endif /* _FSL_UTILS_H */
Loading