summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/imx-wm8962.c
diff options
context:
space:
mode:
authorShengjiu Wang <shengjiu.wang@freescale.com>2016-05-12 17:56:45 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:50:05 +0800
commit3be48438f194ee973dcf35f4662c5f4207d2e9b6 (patch)
tree7d9936ef6cbaba41ffe22d89f8e1f363384a7f73 /sound/soc/fsl/imx-wm8962.c
parent58609cf02e6c569930508e28bd9b6f21c816ede8 (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.c88
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;