summaryrefslogtreecommitdiff
path: root/sound/soc/fsl/imx-cdnhdmi.c
diff options
context:
space:
mode:
authorShengjiu Wang <shengjiu.wang@nxp.com>2018-02-26 15:13:02 +0800
committerDong Aisheng <aisheng.dong@nxp.com>2019-11-25 15:52:33 +0800
commit3c4981dfe077ba6f1bf10ed07f44f5c1d1e03aef (patch)
treec25b117f668f10b3fbb2dbdac371d44bc59a97fe /sound/soc/fsl/imx-cdnhdmi.c
parent7ffc2895efcae28f174dc36081f262c45b1061af (diff)
MLK-17620-2: ASoC: imx-cdnhdmi: switch to generic hdmi codec
switch to generic hdmi codec, which provide the api for get the edid information. Add snd controls which is the interface for user to query the HDMI capibility. ( channels, rates, formats) Signed-off-by: Shengjiu Wang <shengjiu.wang@nxp.com> Reviewed-by: Viorel Suman <viorel.suman@nxp.com>
Diffstat (limited to 'sound/soc/fsl/imx-cdnhdmi.c')
-rw-r--r--sound/soc/fsl/imx-cdnhdmi.c215
1 files changed, 195 insertions, 20 deletions
diff --git a/sound/soc/fsl/imx-cdnhdmi.c b/sound/soc/fsl/imx-cdnhdmi.c
index 0bd7278fe60b..a40230ee1f7b 100644
--- a/sound/soc/fsl/imx-cdnhdmi.c
+++ b/sound/soc/fsl/imx-cdnhdmi.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2015-2016 Freescale Semiconductor, Inc.
+ * Copyright 2017-2018 NXP
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
@@ -21,9 +21,8 @@
#include <sound/control.h>
#include <sound/pcm_params.h>
#include <sound/soc-dapm.h>
-#include "../../../drivers/mxc/hdp/API_Audio.h"
+#include <sound/hdmi-codec.h>
#include "../../../drivers/gpu/drm/imx/hdp/imx-hdp.h"
-#include "../../../drivers/video/fbdev/mxc/API_AFE_t28hpc_hdmitx.h"
#define SUPPORT_RATE_NUM 10
#define SUPPORT_CHANNEL_NUM 10
@@ -34,6 +33,13 @@ struct imx_cdnhdmi_data {
int protocol;
u32 support_rates[SUPPORT_RATE_NUM];
u32 support_rates_num;
+ u32 support_channels[SUPPORT_CHANNEL_NUM];
+ u32 support_channels_num;
+ u32 edid_rates[SUPPORT_RATE_NUM];
+ u32 edid_rates_count;
+ u32 edid_channels[SUPPORT_CHANNEL_NUM];
+ u32 edid_channels_count;
+ uint8_t eld[MAX_ELD_BYTES];
};
static int imx_cdnhdmi_startup(struct snd_pcm_substream *substream)
@@ -44,7 +50,6 @@ static int imx_cdnhdmi_startup(struct snd_pcm_substream *substream)
struct imx_cdnhdmi_data *data = snd_soc_card_get_drvdata(card);
static struct snd_pcm_hw_constraint_list constraint_rates;
static struct snd_pcm_hw_constraint_list constraint_channels;
- static u32 support_channels[SUPPORT_CHANNEL_NUM];
int ret;
constraint_rates.list = data->support_rates;
@@ -55,11 +60,8 @@ static int imx_cdnhdmi_startup(struct snd_pcm_substream *substream)
if (ret)
return ret;
- support_channels[0] = 2;
- support_channels[1] = 4;
- support_channels[2] = 8;
- constraint_channels.list = support_channels;
- constraint_channels.count = 3;
+ constraint_channels.list = data->support_channels;
+ constraint_channels.count = data->support_channels_num;
ret = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
&constraint_channels);
@@ -76,10 +78,6 @@ static int imx_cdnhdmi_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
struct snd_soc_card *card = rtd->card;
struct device *dev = card->dev;
- unsigned int sample_rate = params_rate(params);
- unsigned int channels = params_channels(params);
- unsigned int width = params_physical_width(params);
- struct imx_cdnhdmi_data *data = snd_soc_card_get_drvdata(card);
int ret;
/* set cpu DAI configuration */
@@ -104,11 +102,6 @@ static int imx_cdnhdmi_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- if (data->protocol == 1)
- imx_hdp_audio(AUDIO_TYPE_I2S, sample_rate, channels, width);
- else
- imx_hdmi_audio(AUDIO_TYPE_I2S, sample_rate, channels, width);
-
return 0;
}
@@ -117,6 +110,181 @@ static struct snd_soc_ops imx_cdnhdmi_ops = {
.hw_params = imx_cdnhdmi_hw_params,
};
+static const unsigned int eld_rates[] = {
+ 32000,
+ 44100,
+ 48000,
+ 88200,
+ 96000,
+ 176400,
+ 192000,
+};
+
+static unsigned int sad_max_channels(const u8 *sad)
+{
+ return 1 + (sad[0] & 7);
+}
+
+static int get_edid_info(struct snd_soc_card *card)
+{
+ struct snd_soc_pcm_runtime *rtd = list_first_entry(
+ &card->rtd_list, struct snd_soc_pcm_runtime, list);
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct hdmi_codec_pdata *hcd = codec->dev->platform_data;
+ struct imx_cdnhdmi_data *data = snd_soc_card_get_drvdata(card);
+ int i, j, ret;
+ const u8 *sad;
+ unsigned int channel_max = 0;
+ unsigned int rate_mask = 0;
+ unsigned int rate_mask_eld = 0;
+
+ ret = hcd->ops->get_eld(codec->dev->parent, hcd->data,
+ data->eld, sizeof(data->eld));
+ sad = drm_eld_sad(data->eld);
+ if (sad) {
+ for (j = 0; j < data->support_rates_num; j++) {
+ for (i = 0; i < ARRAY_SIZE(eld_rates); i++)
+ if (eld_rates[i] == data->support_rates[j])
+ rate_mask |= BIT(i);
+ }
+
+ for (i = drm_eld_sad_count(data->eld); i > 0; i--, sad += 3) {
+ if (rate_mask & sad[1])
+ channel_max = max(channel_max, sad_max_channels(sad));
+
+ if (sad_max_channels(sad) >= 2)
+ rate_mask_eld |= sad[1];
+ }
+ }
+
+ rate_mask = rate_mask & rate_mask_eld;
+
+ data->edid_rates_count = 0;
+ data->edid_channels_count = 0;
+
+ for (i = 0; i < ARRAY_SIZE(eld_rates); i++) {
+ if (rate_mask & BIT(i)) {
+ data->edid_rates[data->edid_rates_count] = eld_rates[i];
+ data->edid_rates_count++;
+ }
+ }
+
+ for (i = 0; i < data->support_channels_num; i++) {
+ if (data->support_channels[i] <= channel_max) {
+ data->edid_channels[data->edid_channels_count]
+ = data->support_channels[i];
+ data->edid_channels_count++;
+ }
+ }
+
+ return 0;
+}
+
+static int imx_cdnhdmi_channels_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct imx_cdnhdmi_data *data = snd_soc_card_get_drvdata(card);
+
+ get_edid_info(card);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = data->edid_channels_count;
+
+ return 0;
+}
+
+static int imx_cdnhdmi_channels_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uvalue)
+{
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct imx_cdnhdmi_data *data = snd_soc_card_get_drvdata(card);
+ int i;
+
+ get_edid_info(card);
+
+ for (i = 0 ; i < data->edid_channels_count ; i++)
+ uvalue->value.integer.value[i] = data->edid_channels[i];
+
+ return 0;
+}
+
+static int imx_cdnhdmi_rates_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct imx_cdnhdmi_data *data = snd_soc_card_get_drvdata(card);
+
+ get_edid_info(card);
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = data->edid_rates_count;
+
+ return 0;
+}
+
+static int imx_cdnhdmi_rates_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uvalue)
+{
+ struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+ struct imx_cdnhdmi_data *data = snd_soc_card_get_drvdata(card);
+ int i;
+
+ get_edid_info(card);
+
+ for (i = 0 ; i < data->edid_rates_count; i++)
+ uvalue->value.integer.value[i] = data->edid_rates[i];
+
+ return 0;
+}
+
+static int imx_cdnhdmi_formats_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 3;
+
+ return 0;
+}
+
+static int imx_cdnhdmi_formats_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *uvalue)
+{
+ uvalue->value.integer.value[0] = 16;
+ uvalue->value.integer.value[1] = 24;
+ uvalue->value.integer.value[2] = 32;
+
+ return 0;
+}
+
+static struct snd_kcontrol_new imx_cdnhdmi_ctrls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "HDMI Support Channels",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = imx_cdnhdmi_channels_info,
+ .get = imx_cdnhdmi_channels_get,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "HDMI Support Rates",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = imx_cdnhdmi_rates_info,
+ .get = imx_cdnhdmi_rates_get,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "HDMI Support Formats",
+ .access = SNDRV_CTL_ELEM_ACCESS_READ |
+ SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .info = imx_cdnhdmi_formats_info,
+ .get = imx_cdnhdmi_formats_get,
+ },
+};
+
static int imx_cdnhdmi_probe(struct platform_device *pdev)
{
struct device_node *cpu_np, *cdnhdmi_np = NULL;
@@ -163,13 +331,18 @@ static int imx_cdnhdmi_probe(struct platform_device *pdev)
data->support_rates_num = 4;
}
+ data->support_channels[0] = 2;
+ data->support_channels[1] = 4;
+ data->support_channels[2] = 8;
+ data->support_channels_num = 3;
+
of_property_read_u32(pdev->dev.of_node, "protocol",
&data->protocol);
data->dai.name = "imx8 hdmi";
data->dai.stream_name = "imx8 hdmi";
- data->dai.codec_dai_name = "snd-soc-dummy-dai";
- data->dai.codec_name = "snd-soc-dummy";
+ data->dai.codec_dai_name = "hdmi-hifi.0";
+ data->dai.codec_name = "hdmi-audio-codec";
data->dai.cpu_dai_name = dev_name(&cpu_pdev->dev);
data->dai.platform_of_node = cpu_np;
data->dai.ops = &imx_cdnhdmi_ops;
@@ -186,6 +359,8 @@ static int imx_cdnhdmi_probe(struct platform_device *pdev)
goto fail;
data->card.num_links = 1;
data->card.dai_link = &data->dai;
+ data->card.controls = imx_cdnhdmi_ctrls,
+ data->card.num_controls = ARRAY_SIZE(imx_cdnhdmi_ctrls),
platform_set_drvdata(pdev, &data->card);
snd_soc_card_set_drvdata(&data->card, data);