diff options
author | Shengjiu Wang <shengjiu.wang@freescale.com> | 2016-05-12 17:56:45 +0800 |
---|---|---|
committer | Dong Aisheng <aisheng.dong@nxp.com> | 2019-11-25 15:50:05 +0800 |
commit | 3be48438f194ee973dcf35f4662c5f4207d2e9b6 (patch) | |
tree | 7d9936ef6cbaba41ffe22d89f8e1f363384a7f73 /sound/soc/fsl/imx-wm8962.c | |
parent | 58609cf02e6c569930508e28bd9b6f21c816ede8 (diff) |
MLK-12787-1: ASoC: imx-wm8962: Add codec-master property
Add codec-master property for imx-wm8962. If set this in device
tree, the codec will work as master, if don't set it, the cpu dai
will work as master.
Signed-off-by: Shengjiu Wang <shengjiu.wang@freescale.com>
Diffstat (limited to 'sound/soc/fsl/imx-wm8962.c')
-rw-r--r-- | sound/soc/fsl/imx-wm8962.c | 88 |
1 files changed, 68 insertions, 20 deletions
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c index 03c32dd58231..b770963d18bb 100644 --- a/sound/soc/fsl/imx-wm8962.c +++ b/sound/soc/fsl/imx-wm8962.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2013-2015 Freescale Semiconductor, Inc. + * Copyright (C) 2013-2016 Freescale Semiconductor, Inc. * * Based on imx-sgtl5000.c * Copyright (C) 2012 Freescale Semiconductor, Inc. @@ -38,6 +38,7 @@ struct imx_wm8962_data { char codec_dai_name[DAI_NAME_SIZE]; char platform_name[DAI_NAME_SIZE]; unsigned int clk_frequency; + bool is_codec_master; }; struct imx_priv { @@ -184,6 +185,31 @@ static const struct snd_soc_dapm_widget imx_wm8962_dapm_widgets[] = { SND_SOC_DAPM_MIC("DMIC", NULL), }; +static u32 imx_wm8962_rates[] = {32000, 48000, 96000}; +static struct snd_pcm_hw_constraint_list imx_wm8962_rate_constraints = { + .count = ARRAY_SIZE(imx_wm8962_rates), + .list = imx_wm8962_rates, +}; + +static int imx_hifi_startup(struct snd_pcm_substream *substream) +{ + struct snd_pcm_runtime *runtime = substream->runtime; + struct snd_soc_pcm_runtime *rtd = substream->private_data; + struct snd_soc_card *card = rtd->card; + struct imx_wm8962_data *data = snd_soc_card_get_drvdata(card); + int ret; + + if (!data->is_codec_master) { + ret = snd_pcm_hw_constraint_list(runtime, 0, + SNDRV_PCM_HW_PARAM_RATE, + &imx_wm8962_rate_constraints); + if (ret) + return ret; + } + + return 0; +} + #ifdef CONFIG_SND_SOC_IMX_WM8962_ANDROID static int imx_hifi_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *params) @@ -198,8 +224,12 @@ static int imx_hifi_hw_params(struct snd_pcm_substream *substream, sample_rate = params_rate(params); sample_format = params_format(params); - dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; + if (data->is_codec_master) + dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; + else + dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, dai_format); @@ -212,6 +242,7 @@ static int imx_hifi_hw_params(struct snd_pcm_substream *substream, } static struct snd_soc_ops imx_hifi_ops = { + .startup = imx_hifi_startup, .hw_params = imx_hifi_hw_params, }; @@ -308,8 +339,12 @@ static int imx_hifi_hw_params(struct snd_pcm_substream *substream, return 0; } - dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; + if (data->is_codec_master) + dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBM_CFM; + else + dai_format = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | + SND_SOC_DAIFMT_CBS_CFS; /* set codec DAI configuration */ ret = snd_soc_dai_set_fmt(codec_dai, dai_format); @@ -388,6 +423,7 @@ static int imx_hifi_hw_free(struct snd_pcm_substream *substream) } static struct snd_soc_ops imx_hifi_ops = { + .startup = imx_hifi_startup, .hw_params = imx_hifi_hw_params, .hw_free = imx_hifi_hw_free, }; @@ -528,7 +564,7 @@ static int imx_wm8962_probe(struct platform_device *pdev) struct i2c_client *codec_dev; struct imx_wm8962_data *data; struct clk *codec_clk; - int int_port, ext_port; + int int_port, ext_port, tmp_port; int ret; struct platform_device *asrc_pdev = NULL; struct device_node *asrc_np; @@ -537,6 +573,15 @@ static int imx_wm8962_probe(struct platform_device *pdev) priv->pdev = pdev; priv->asrc_pdev = NULL; + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); + if (!data) { + ret = -ENOMEM; + goto fail; + } + + if (of_property_read_bool(pdev->dev.of_node, "codec-master")) + data->is_codec_master = true; + cpu_np = of_parse_phandle(pdev->dev.of_node, "cpu-dai", 0); if (!cpu_np) { dev_err(&pdev->dev, "cpu dai phandle missing or invalid\n"); @@ -564,20 +609,26 @@ static int imx_wm8962_probe(struct platform_device *pdev) */ int_port--; ext_port--; - ret = imx_audmux_v2_configure_port(int_port, + if (data->is_codec_master) { + tmp_port = int_port; + int_port = ext_port; + ext_port = tmp_port; + } + + ret = imx_audmux_v2_configure_port(ext_port, IMX_AUDMUX_V2_PTCR_SYN | - IMX_AUDMUX_V2_PTCR_TFSEL(ext_port) | - IMX_AUDMUX_V2_PTCR_TCSEL(ext_port) | + IMX_AUDMUX_V2_PTCR_TFSEL(int_port) | + IMX_AUDMUX_V2_PTCR_TCSEL(int_port) | IMX_AUDMUX_V2_PTCR_TFSDIR | IMX_AUDMUX_V2_PTCR_TCLKDIR, - IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); + IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); if (ret) { dev_err(&pdev->dev, "audmux internal port setup failed\n"); goto fail; } - ret = imx_audmux_v2_configure_port(ext_port, + ret = imx_audmux_v2_configure_port(int_port, IMX_AUDMUX_V2_PTCR_SYN, - IMX_AUDMUX_V2_PDCR_RXDSEL(int_port)); + IMX_AUDMUX_V2_PDCR_RXDSEL(ext_port)); if (ret) { dev_err(&pdev->dev, "audmux external port setup failed\n"); goto fail; @@ -613,12 +664,6 @@ audmux_bypass: priv->first_stream = NULL; priv->second_stream = NULL; - data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); - if (!data) { - ret = -ENOMEM; - goto fail; - } - codec_clk = clk_get(&codec_dev->dev, NULL); if (IS_ERR(codec_clk)) { ret = PTR_ERR(codec_clk); @@ -644,8 +689,11 @@ audmux_bypass: data->dai[0].cpu_dai_name = dev_name(&cpu_pdev->dev); data->dai[0].platform_of_node = cpu_np; data->dai[0].ops = &imx_hifi_ops; - data->dai[0].dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF | - SND_SOC_DAIFMT_CBM_CFM; + data->dai[0].dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF; + if (data->is_codec_master) + data->dai[0].dai_fmt |= SND_SOC_DAIFMT_CBM_CFM; + else + data->dai[0].dai_fmt |= SND_SOC_DAIFMT_CBS_CFS; data->card.num_links = 1; |