summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/imx-ak4458.c
diff options
context:
space:
mode:
authorViorel Suman <viorel.suman@nxp.com>2018-08-27 14:09:25 +0300
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:50:40 +0800
commite49e74b10a1a3889efee3ea51532e3b544db7290 (patch)
tree408d02f6d986029d30314c65b13722ddfc29c81f /sound/soc/fsl/imx-ak4458.c
parent38e7229732e6308197343b9e81ffc33e6a4232a5 (diff)
MLK-18898-2: ASoC: imx-ak4458: refine mclk rate calculation
The existing implementation calculates mclk rate as function of audio sample rate multiplied to multiplier taken from Table 5. However this is not accurate for Manual Setting Mode - tables 3 & 4 from AK4458 RM defines rate (LRCK/FS) and frame width (MCLK/16fs..1152fs) ranges as parameters to calculate mclk frequency. Aside of this - adjust bclk:mclk ratio from machine driver as function of "compatible" id. Signed-off-by: Viorel Suman <viorel.suman@nxp.com> (cherry picked from commit 527b8b7032dcb75c14bb2790330ab96743d83b16)
Diffstat (limited to 'sound/soc/fsl/imx-ak4458.c')
-rw-r--r--sound/soc/fsl/imx-ak4458.c132
1 files changed, 70 insertions, 62 deletions
diff --git a/sound/soc/fsl/imx-ak4458.c b/sound/soc/fsl/imx-ak4458.c
index 83086fb61e62..0dd3e8a15983 100644
--- a/sound/soc/fsl/imx-ak4458.c
+++ b/sound/soc/fsl/imx-ak4458.c
@@ -33,31 +33,43 @@ struct imx_ak4458_data {
int pdn_gpio;
unsigned int slots;
unsigned int slot_width;
-};
-
-struct imx_ak4458_fs_mul {
- unsigned int min;
- unsigned int max;
- unsigned int mul;
+ bool one2one_ratio;
};
static struct snd_soc_dapm_widget imx_ak4458_dapm_widgets[] = {
SND_SOC_DAPM_LINE("Line Out", NULL),
};
-static const struct imx_ak4458_fs_mul fs_mul[] = {
- /*
- * Table 2 - mapping multiplier and speed mode
- * Tables 3 & 4 - mapping speed mode and LRCK fs
- */
- { .min = 8000, .max = 48000, .mul = 1024 }, /* Normal */
- { .min = 88200, .max = 96000, .mul = 512 }, /* Double */
- { .min = 176400, .max = 192000, .mul = 256 }, /* Quad */
- { .min = 352800, .max = 384000, .mul = 128 }, /* Oct */
- { .min = 705600, .max = 768000, .mul = 64 }, /* Hex */
+/**
+ * Tables 3 & 4 - mapping LRCK fs and frame width
+ */
+static const struct imx_ak4458_fs_map {
+ unsigned int rmin;
+ unsigned int rmax;
+ unsigned int wmin;
+ unsigned int wmax;
+} fs_map[] = {
+ /* Normal, < 32kHz */
+ { .rmin = 8000, .rmax = 24000, .wmin = 1024, .wmax = 1024, },
+ /* Normal, 32kHz */
+ { .rmin = 32000, .rmax = 32000, .wmin = 256, .wmax = 1024, },
+ /* Normal */
+ { .rmin = 44100, .rmax = 48000, .wmin = 256, .wmax = 768, },
+ /* Double */
+ { .rmin = 88200, .rmax = 96000, .wmin = 256, .wmax = 512, },
+ /* Quad */
+ { .rmin = 176400, .rmax = 192000, .wmin = 128, .wmax = 256, },
+ /* Oct */
+ { .rmin = 352800, .rmax = 384000, .wmin = 32, .wmax = 128, },
+ /* Hex */
+ { .rmin = 705600, .rmax = 768000, .wmin = 16, .wmax = 64, },
};
-static const struct imx_ak4458_fs_mul fs_mul_tdm[] = {
+static const struct imx_ak4458_fs_mul {
+ unsigned int min;
+ unsigned int max;
+ unsigned int mul;
+} fs_mul_tdm[] = {
/*
* Table 13 - Audio Interface Format
* For TDM mode, MCLK should is set to
@@ -94,9 +106,8 @@ static unsigned long ak4458_get_mclk_rate(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct imx_ak4458_data *data = snd_soc_card_get_drvdata(rtd->card);
unsigned int rate = params_rate(params);
- int i;
- int mode;
- unsigned int freq = 0; /* Let DAI manage clk frequency by default */
+ unsigned int width = data->slots * data->slot_width;
+ int i, mode;
if (data->tdm_mode) {
/* can be 128, 256 or 512 */
@@ -106,20 +117,24 @@ static unsigned long ak4458_get_mclk_rate(struct snd_pcm_substream *substream,
/* min = max = slots * slots_width */
if (mode != fs_mul_tdm[i].min)
continue;
- freq = rate * fs_mul_tdm[i].mul;
- break;
+ return rate * fs_mul_tdm[i].mul;
}
} else {
- for (i = 0; i < ARRAY_SIZE(fs_mul); i++) {
- if (rate < fs_mul[i].min || rate > fs_mul[i].max)
- continue;
- /* rate is within min and max */
- freq = rate * fs_mul[i].mul;
- break;
+ for (i = 0; i < ARRAY_SIZE(fs_map); i++) {
+ if (rate >= fs_map[i].rmin && rate <= fs_map[i].rmax) {
+ width = max(width, fs_map[i].wmin);
+ width = min(width, fs_map[i].wmax);
+
+ /* Adjust SAI bclk:mclk ratio */
+ width *= data->one2one_ratio ? 1 : 2;
+
+ return rate * width;
+ }
}
}
- return freq;
+ /* Let DAI manage clk frequency by default */
+ return 0;
}
static int imx_aif_hw_params(struct snd_pcm_substream *substream,
@@ -128,72 +143,62 @@ static int imx_aif_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_card *card = rtd->card;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
struct device *dev = card->dev;
struct imx_ak4458_data *data = snd_soc_card_get_drvdata(card);
unsigned int channels = params_channels(params);
- unsigned int fmt;
+ unsigned int fmt = SND_SOC_DAIFMT_NB_NF | SND_SOC_DAIFMT_CBS_CFS;
unsigned long mclk_freq;
- int ret;
- int i;
+ int ret, i;
- if (data->tdm_mode)
- fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
- else
- fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
- SND_SOC_DAIFMT_CBS_CFS;
+ if (data->tdm_mode) {
+ data->slots = 8;
+ data->slot_width = 32;
+ } else {
+ data->slots = 2;
+ data->slot_width = params_physical_width(params);
+ }
+
+ fmt |= data->tdm_mode ? SND_SOC_DAIFMT_DSP_B : SND_SOC_DAIFMT_I2S;
ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
if (ret) {
dev_err(dev, "failed to set cpu dai fmt: %d\n", ret);
return ret;
}
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai,
+ BIT(channels) - 1, BIT(channels) - 1,
+ data->slots, data->slot_width);
+ if (ret) {
+ dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret);
+ return ret;
+ }
for (i = 0; i < rtd->num_codecs; i++) {
struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
ret = snd_soc_dai_set_fmt(codec_dai, fmt);
if (ret) {
- dev_err(dev, "failed to set codec dai fmt: %d\n", ret);
+ dev_err(dev, "failed to set codec dai[%d] fmt: %d\n",
+ i, ret);
return ret;
}
- }
-
- if (data->tdm_mode) {
- data->slots = 8;
- data->slot_width = 32;
-
ret = snd_soc_dai_set_tdm_slot(codec_dai,
BIT(channels) - 1, BIT(channels) - 1,
data->slots, data->slot_width);
if (ret) {
- dev_err(dev, "failed to set codec dai tdm slot: %d\n", ret);
+ dev_err(dev, "failed to set codec dai[%d] tdm slot: %d\n",
+ i, ret);
return ret;
}
- } else {
- data->slots = 2;
- data->slot_width = params_physical_width(params);
- }
-
- ret = snd_soc_dai_set_tdm_slot(cpu_dai,
- BIT(channels) - 1, BIT(channels) - 1,
- data->slots, data->slot_width);
- if (ret) {
- dev_err(dev, "failed to set cpu dai tdm slot: %d\n", ret);
- return ret;
}
/* set MCLK freq */
mclk_freq = ak4458_get_mclk_rate(substream, params);
ret = snd_soc_dai_set_sysclk(cpu_dai, FSL_SAI_CLK_MAST1, mclk_freq,
SND_SOC_CLOCK_OUT);
- if (ret < 0) {
+ if (ret < 0)
dev_err(dev, "failed to set cpui dai mclk1 rate (%lu): %d\n",
mclk_freq, ret);
- return ret;
- }
-
return ret;
}
@@ -328,6 +333,8 @@ static int imx_ak4458_probe(struct platform_device *pdev)
priv->card.num_dapm_widgets = ARRAY_SIZE(imx_ak4458_dapm_widgets);
priv->card.codec_conf = priv->codec_conf;
priv->card.num_configs = priv->num_codec_conf;
+ priv->one2one_ratio = !of_device_is_compatible(pdev->dev.of_node,
+ "fsl,imx-audio-ak4458-mq");
priv->pdn_gpio = of_get_named_gpio(pdev->dev.of_node, "ak4458,pdn-gpio", 0);
if (gpio_is_valid(priv->pdn_gpio)) {
@@ -370,6 +377,7 @@ fail:
static const struct of_device_id imx_ak4458_dt_ids[] = {
{ .compatible = "fsl,imx-audio-ak4458", },
+ { .compatible = "fsl,imx-audio-ak4458-mq", },
{ },
};
MODULE_DEVICE_TABLE(of, imx_ak4458_dt_ids);