diff options
Diffstat (limited to 'sound/soc/fsl/fsl_asrc.c')
-rw-r--r-- | sound/soc/fsl/fsl_asrc.c | 125 |
1 files changed, 105 insertions, 20 deletions
diff --git a/sound/soc/fsl/fsl_asrc.c b/sound/soc/fsl/fsl_asrc.c index a3cfceea7d2f..0dcebc24c312 100644 --- a/sound/soc/fsl/fsl_asrc.c +++ b/sound/soc/fsl/fsl_asrc.c @@ -41,26 +41,65 @@ static struct snd_pcm_hw_constraint_list fsl_asrc_rate_constraints = { * The following tables map the relationship between asrc_inclk/asrc_outclk in * fsl_asrc.h and the registers of ASRCSR */ -static unsigned char input_clk_map_imx35[] = { +static unsigned char input_clk_map_imx35[ASRC_CLK_MAP_LEN] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, }; -static unsigned char output_clk_map_imx35[] = { +static unsigned char output_clk_map_imx35[ASRC_CLK_MAP_LEN] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, }; /* i.MX53 uses the same map for input and output */ -static unsigned char input_clk_map_imx53[] = { +static unsigned char input_clk_map_imx53[ASRC_CLK_MAP_LEN] = { /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 0x0, 0x1, 0x2, 0x7, 0x4, 0x5, 0x6, 0x3, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xe, 0xd, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, }; -static unsigned char output_clk_map_imx53[] = { +static unsigned char output_clk_map_imx53[ASRC_CLK_MAP_LEN] = { /* 0x0 0x1 0x2 0x3 0x4 0x5 0x6 0x7 0x8 0x9 0xa 0xb 0xc 0xd 0xe 0xf */ 0x8, 0x9, 0xa, 0x7, 0xc, 0x5, 0x6, 0xb, 0x0, 0x1, 0x2, 0x3, 0x4, 0xf, 0xe, 0xd, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, + 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, 0x7, }; -static unsigned char *clk_map[2]; +/** + * i.MX8QM/i.MX8QXP uses the same map for input and output. + * clk_map_imx8qm[0] is for i.MX8QM asrc0 + * clk_map_imx8qm[1] is for i.MX8QM asrc1 + * clk_map_imx8qxp[0] is for i.MX8QXP asrc0 + * clk_map_imx8qxp[1] is for i.MX8QXP asrc1 + */ +static unsigned char clk_map_imx8qm[2][ASRC_CLK_MAP_LEN] = { + { + 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, + 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, + }, + { + 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, + 0x0, 0x1, 0x2, 0x3, 0xb, 0xc, 0xf, 0xf, 0xd, 0xe, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, + 0x4, 0x5, 0x6, 0xf, 0x8, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, + }, +}; + +static unsigned char clk_map_imx8qxp[2][ASRC_CLK_MAP_LEN] = { + { + 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, + 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0xf, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xf, 0xf, + 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, + }, + { + 0xf, 0xf, 0xf, 0xf, 0xf, 0x7, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0x0, + 0x0, 0x1, 0x2, 0x3, 0x7, 0x8, 0xf, 0xf, 0x9, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, + 0xf, 0xf, 0x6, 0xf, 0xf, 0xf, 0xa, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, 0xf, + }, +}; /** * Select the pre-processing and post-processing options @@ -353,8 +392,8 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) } /* Validate input and output clock sources */ - clk_index[IN] = clk_map[IN][config->inclk]; - clk_index[OUT] = clk_map[OUT][config->outclk]; + clk_index[IN] = asrc_priv->clk_map[IN][config->inclk]; + clk_index[OUT] = asrc_priv->clk_map[OUT][config->outclk]; /* We only have output clock for ideal ratio mode */ clk = asrc_priv->asrck_clk[clk_index[ideal ? OUT : IN]]; @@ -398,13 +437,13 @@ static int fsl_asrc_config_pair(struct fsl_asrc_pair *pair, bool use_ideal_rate) /* Set the channel number */ channels = config->channel_num; - if (asrc_priv->channel_bits < 4) + if (asrc_priv->soc->channel_bits < 4) channels /= 2; /* Update channels for current pair */ regmap_update_bits(asrc_priv->regmap, REG_ASRCNCR, - ASRCNCR_ANCi_MASK(index, asrc_priv->channel_bits), - ASRCNCR_ANCi(index, channels, asrc_priv->channel_bits)); + ASRCNCR_ANCi_MASK(index, asrc_priv->soc->channel_bits), + ASRCNCR_ANCi(index, channels, asrc_priv->soc->channel_bits)); /* Default setting: Automatic selection for processing mode */ regmap_update_bits(asrc_priv->regmap, REG_ASRCTR, @@ -531,7 +570,7 @@ static int fsl_asrc_dai_startup(struct snd_pcm_substream *substream, struct fsl_asrc *asrc_priv = snd_soc_dai_get_drvdata(dai); /* Odd channel number is not valid for older ASRC (channel_bits==3) */ - if (asrc_priv->channel_bits == 3) + if (asrc_priv->soc->channel_bits == 3) snd_pcm_hw_constraint_step(substream->runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, 2); @@ -905,6 +944,7 @@ static int fsl_asrc_probe(struct platform_device *pdev) struct resource *res; void __iomem *regs; int irq, ret, i; + u32 map_idx; char tmp[16]; asrc_priv = devm_kzalloc(&pdev->dev, sizeof(*asrc_priv), GFP_KERNEL); @@ -964,14 +1004,37 @@ static int fsl_asrc_probe(struct platform_device *pdev) } } + asrc_priv->soc = of_device_get_match_data(&pdev->dev); + if (!asrc_priv->soc) { + dev_err(&pdev->dev, "failed to get soc data\n"); + return -ENODEV; + } + if (of_device_is_compatible(np, "fsl,imx35-asrc")) { - asrc_priv->channel_bits = 3; - clk_map[IN] = input_clk_map_imx35; - clk_map[OUT] = output_clk_map_imx35; - } else { - asrc_priv->channel_bits = 4; - clk_map[IN] = input_clk_map_imx53; - clk_map[OUT] = output_clk_map_imx53; + asrc_priv->clk_map[IN] = input_clk_map_imx35; + asrc_priv->clk_map[OUT] = output_clk_map_imx35; + } else if (of_device_is_compatible(np, "fsl,imx53-asrc")) { + asrc_priv->clk_map[IN] = input_clk_map_imx53; + asrc_priv->clk_map[OUT] = output_clk_map_imx53; + } else if (of_device_is_compatible(np, "fsl,imx8qm-asrc") || + of_device_is_compatible(np, "fsl,imx8qxp-asrc")) { + ret = of_property_read_u32(np, "fsl,asrc-clk-map", &map_idx); + if (ret) { + dev_err(&pdev->dev, "failed to get clk map index\n"); + return ret; + } + + if (map_idx > 1) { + dev_err(&pdev->dev, "unsupported clk map index\n"); + return -EINVAL; + } + if (of_device_is_compatible(np, "fsl,imx8qm-asrc")) { + asrc_priv->clk_map[IN] = clk_map_imx8qm[map_idx]; + asrc_priv->clk_map[OUT] = clk_map_imx8qm[map_idx]; + } else { + asrc_priv->clk_map[IN] = clk_map_imx8qxp[map_idx]; + asrc_priv->clk_map[OUT] = clk_map_imx8qxp[map_idx]; + } } ret = fsl_asrc_init(asrc_priv); @@ -1113,9 +1176,31 @@ static const struct dev_pm_ops fsl_asrc_pm = { SET_SYSTEM_SLEEP_PM_OPS(fsl_asrc_suspend, fsl_asrc_resume) }; +static const struct fsl_asrc_soc_data fsl_asrc_imx35_data = { + .use_edma = false, + .channel_bits = 3, +}; + +static const struct fsl_asrc_soc_data fsl_asrc_imx53_data = { + .use_edma = false, + .channel_bits = 4, +}; + +static const struct fsl_asrc_soc_data fsl_asrc_imx8qm_data = { + .use_edma = true, + .channel_bits = 4, +}; + +static const struct fsl_asrc_soc_data fsl_asrc_imx8qxp_data = { + .use_edma = true, + .channel_bits = 4, +}; + static const struct of_device_id fsl_asrc_ids[] = { - { .compatible = "fsl,imx35-asrc", }, - { .compatible = "fsl,imx53-asrc", }, + { .compatible = "fsl,imx35-asrc", .data = &fsl_asrc_imx35_data }, + { .compatible = "fsl,imx53-asrc", .data = &fsl_asrc_imx53_data }, + { .compatible = "fsl,imx8qm-asrc", .data = &fsl_asrc_imx8qm_data }, + { .compatible = "fsl,imx8qxp-asrc", .data = &fsl_asrc_imx8qxp_data }, {} }; MODULE_DEVICE_TABLE(of, fsl_asrc_ids); |