diff options
-rw-r--r-- | Documentation/devicetree/bindings/sound/imx-audio-ak4458.txt | 2 | ||||
-rw-r--r-- | arch/arm64/boot/dts/freescale/fsl-imx8mq-evk.dts | 2 | ||||
-rw-r--r-- | sound/soc/fsl/imx-ak4458.c | 132 |
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); |