summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);