summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorViorel Suman <viorel.suman@nxp.com>2018-08-27 14:09:25 +0300
committerViorel Suman <viorel.suman@nxp.com>2018-09-05 10:43:48 +0300
commit8b0307ce5f98c04e06d61ae08afe7d268207c7ce (patch)
treeb6f7b5e61145fc7833e82236245cbbd0019d1a24
parent9eeab5c9bbcf7fc81d08ef0a67250c987e6ef452 (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)
-rw-r--r--Documentation/devicetree/bindings/sound/imx-audio-ak4458.txt2
-rw-r--r--arch/arm64/boot/dts/freescale/fsl-imx8mq-evk.dts2
-rw-r--r--sound/soc/fsl/imx-ak4458.c132
3 files changed, 72 insertions, 64 deletions
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-ak4458.txt b/Documentation/devicetree/bindings/sound/imx-audio-ak4458.txt
index a20de9cc72c4..a442d3edd62d 100644
--- a/Documentation/devicetree/bindings/sound/imx-audio-ak4458.txt
+++ b/Documentation/devicetree/bindings/sound/imx-audio-ak4458.txt
@@ -2,7 +2,7 @@ Freescale i.MX audio complex with AK4458 DAC
Required properties:
-- compatible : "fsl,imx-audio-ak4458"
+- compatible : "fsl,imx-audio-ak4458", "fsl,imx-audio-ak4458-mq"
- model : The user-visible name of this sound complex
- audio-cpu : The phandle of CPU DAI
- audio-codec : The phandle of the AK4458 audio DAC
diff --git a/arch/arm64/boot/dts/freescale/fsl-imx8mq-evk.dts b/arch/arm64/boot/dts/freescale/fsl-imx8mq-evk.dts
index 9589b81dd2e3..eff0aa628b80 100644
--- a/arch/arm64/boot/dts/freescale/fsl-imx8mq-evk.dts
+++ b/arch/arm64/boot/dts/freescale/fsl-imx8mq-evk.dts
@@ -107,7 +107,7 @@
};
sound-ak4458 {
- compatible = "fsl,imx-audio-ak4458";
+ compatible = "fsl,imx-audio-ak4458-mq";
model = "ak4458-audio";
audio-cpu = <&sai1>;
audio-codec = <&ak4458_1>, <&ak4458_2>;
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);