summaryrefslogtreecommitdiff
path: root/sound
diff options
context:
space:
mode:
authorOla Lilja <ola.o.lilja@stericsson.com>2010-10-01 16:06:57 +0200
committerUlf Hansson <ulf.hansson@stericsson.com>2011-09-19 15:14:42 +0200
commitcdd77f9812464cb56a1cfef29ae9d51199eeb922 (patch)
tree5c908550c419c50fa08d403e0502ef868194d054 /sound
parent80067c6f05647a405bbd1cc7748d9651971012e7 (diff)
Ux500 ASoC: Support for multi-channel audio in AV8100 codec-driver.
The HDMI ASoC-driver can now be configured with 1-8 channels. Configuration is also done by using the HDMI-standard for audio info-frames. Change-Id: Ibc84f2efeb748a1cace08d184dfd387f46c58d7c Signed-off-by: Ola Lilja <ola.o.lilja@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/5915 Reviewed-by: Linus WALLEIJ <linus.walleij@stericsson.com>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/Makefile6
-rw-r--r--sound/soc/codecs/av8100_audio.c245
-rw-r--r--sound/soc/codecs/av8100_audio.h141
-rw-r--r--sound/soc/ux500/Makefile3
-rw-r--r--sound/soc/ux500/ux500_av8100.c159
5 files changed, 455 insertions, 99 deletions
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index f774d716b6b..99bbb804537 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -184,4 +184,8 @@ obj-$(CONFIG_SND_SOC_LM4857) += snd-soc-lm4857.o
obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o
obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.o
obj-$(CONFIG_SND_SOC_WM2000) += snd-soc-wm2000.o
-obj-$(CONFIG_SND_SOC_WM9090) += snd-soc-wm9090.o
+ifdef CONFIG_SND_SOC_UX500_DEBUG
+CFLAGS_av8100_audio.o := -DDEBUG
+CFLAGS_ab3550.o := -DDEBUG
+CFLAGS_cg29xx.o := -DDEBUG
+endif
diff --git a/sound/soc/codecs/av8100_audio.c b/sound/soc/codecs/av8100_audio.c
index 7bcb985b9eb..d85a8ca24e5 100644
--- a/sound/soc/codecs/av8100_audio.c
+++ b/sound/soc/codecs/av8100_audio.c
@@ -28,21 +28,21 @@
#include "av8100_audio.h"
-#define AV8100_SUPPORTED_RATE (SNDRV_PCM_RATE_48000)
-#define AV8100_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE)
+/* codec private data */
+struct av8100_codec_private_data {
+ struct hdmi_audio_settings as;
+};
-static int setupAV8100_stereo(void)
+static int av8100_codec_powerup(void)
{
- union av8100_configuration config;
struct av8100_status status;
int ret;
pr_debug("%s: Enter.\n", __func__);
- /* Startup AV8100 if it is not already started */
status = av8100_status_get();
if (status.av8100_state < AV8100_OPMODE_STANDBY) {
- pr_info("%s: Powering up AV8100.", __func__);
+ pr_debug("%s: Powering up AV8100.", __func__);
ret = av8100_powerup();
if (ret != 0) {
pr_err("%s: Power up AV8100 failed "
@@ -63,11 +63,21 @@ static int setupAV8100_stereo(void)
}
}
- /* Set the HDMI format of AV8100 */
- pr_info("%s: Setting hdmi_format.", __func__);
+ return 0;
+}
+
+static int av8100_codec_setup_hdmi_format(void)
+{
+ union av8100_configuration config;
+ int ret;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ pr_debug("%s: hdmi_mode = AV8100_HDMI_ON.", __func__);
+ pr_debug("%s: hdmi_format = AV8100_HDMI.", __func__);
config.hdmi_format.hdmi_mode = AV8100_HDMI_ON;
config.hdmi_format.hdmi_format = AV8100_HDMI;
- ret = av8100_conf_prep(AV8100_COMMAND_AUDIO_INPUT_FORMAT, &config);
+ ret = av8100_conf_prep(AV8100_COMMAND_HDMI, &config);
if (ret != 0) {
pr_err("%s: Setting hdmi_format failed "
"(av8100_conf_prep returned %d)!\n",
@@ -75,7 +85,7 @@ static int setupAV8100_stereo(void)
ret);
return -EINVAL;
}
- ret = av8100_conf_w(AV8100_COMMAND_AUDIO_INPUT_FORMAT,
+ ret = av8100_conf_w(AV8100_COMMAND_HDMI,
NULL,
NULL,
I2C_INTERFACE);
@@ -87,26 +97,78 @@ static int setupAV8100_stereo(void)
return -EINVAL;
}
- /* Set the audio input format of AV8100 */
- pr_info("%s: Setting audio_input_format.", __func__);
- config.audio_input_format.audio_input_if_format = AV8100_AUDIO_I2SDELAYED_MODE;
- config.audio_input_format.i2s_input_nb = 1;
- config.audio_input_format.sample_audio_freq = AV8100_AUDIO_FREQ_48KHZ;
- config.audio_input_format.audio_word_lg = AV8100_AUDIO_16BITS;
- config.audio_input_format.audio_format = AV8100_AUDIO_LPCM_MODE;
- config.audio_input_format.audio_if_mode = AV8100_AUDIO_MASTER;
- config.audio_input_format.audio_mute = AV8100_AUDIO_MUTE_DISABLE;
- ret = av8100_conf_prep(AV8100_COMMAND_AUDIO_INPUT_FORMAT, &config);
+ return 0;
+}
+
+static int av8100_codec_pcm_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ pr_debug("%s: Enter.\n", __func__);
+
+ return 0;
+}
+
+static int av8100_codec_send_audio_infoframe(struct hdmi_audio_settings *as)
+{
+ union av8100_configuration config;
+ struct av8100_infoframes_format_cmd info_fr;
+ int ret;
+
+ pr_debug("%s: Enter.\n", __func__);
+
+ pr_debug("%s: HDMI-settings:\n", __func__);
+ pr_debug("%s: audio_coding_type = %d\n", __func__, as->audio_coding_type);
+ pr_debug("%s: audio_channel_count = %d\n", __func__, as->audio_channel_count);
+ pr_debug("%s: sampling_frequency = %d\n", __func__, as->sampling_frequency);
+ pr_debug("%s: sample_size = %d\n", __func__, as->sample_size);
+ pr_debug("%s: channel_allocation = %d\n", __func__, as->channel_allocation);
+ pr_debug("%s: level_shift_value = %d\n", __func__, as->level_shift_value);
+ pr_debug("%s: downmix_inhibit = %d\n", __func__, as->downmix_inhibit);
+
+ /* Prepare the infoframe from the hdmi_audio_settings struct */
+ pr_info("%s: Preparing audio info-frame.", __func__);
+ info_fr.type = 0x84;
+ info_fr.version = 0x01;
+ info_fr.length = 0x0a;
+ info_fr.data[0] = (as->audio_coding_type << 4) | as->audio_channel_count;
+ info_fr.data[1] = (as->sampling_frequency << 2) | as->sample_size;
+ info_fr.data[2] = 0;
+ info_fr.data[3] = as->channel_allocation;
+ info_fr.data[4] = ((int)as->downmix_inhibit << 7) |
+ (as->level_shift_value << 3);
+ info_fr.data[5] = 0;
+ info_fr.data[6] = 0;
+ info_fr.data[7] = 0;
+ info_fr.data[8] = 0;
+ info_fr.data[9] = 0;
+ info_fr.crc = info_fr.version +
+ info_fr.length +
+ info_fr.data[0] +
+ info_fr.data[1] +
+ info_fr.data[3] +
+ info_fr.data[4];
+ config.infoframes_format.type = info_fr.type;
+ config.infoframes_format.version = info_fr.version;
+ config.infoframes_format.crc = info_fr.crc;
+ config.infoframes_format.length = info_fr.length;
+ memcpy(&config.infoframes_format.data, info_fr.data, info_fr.length);
+
+ /* Send audio info-frame */
+ pr_info("%s: Sending audio info-frame.", __func__);
+ ret = av8100_conf_prep(AV8100_COMMAND_INFOFRAMES, &config);
if (ret != 0) {
- pr_err("%s: Setting audio_input_format failed "
+ pr_err("%s: Sending audio info-frame failed "
"(av8100_conf_prep returned %d)!\n",
__func__,
ret);
return -EINVAL;
}
- if (av8100_conf_w(AV8100_COMMAND_AUDIO_INPUT_FORMAT,
- NULL, NULL, I2C_INTERFACE) != 0) {
- pr_err("%s: Setting audio_input_format failed "
+ ret = av8100_conf_w(AV8100_COMMAND_INFOFRAMES,
+ NULL,
+ NULL,
+ I2C_INTERFACE);
+ if (ret != 0) {
+ pr_err("%s: Sending audio info-frame failed "
"(av8100_conf_w returned %d)!\n",
__func__,
ret);
@@ -116,11 +178,23 @@ static int setupAV8100_stereo(void)
return 0;
}
-static int av8100_codec_pcm_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
+int av8100_codec_change_hdmi_audio_settings(struct snd_pcm_substream *substream,
+ struct hdmi_audio_settings *as)
{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct av8100_codec_private_data *av8100_codec_priv = codec->private_data;
+
pr_debug("%s: Enter.\n", __func__);
+ av8100_codec_priv->as.audio_coding_type = as->audio_coding_type;
+ av8100_codec_priv->as.audio_channel_count = as->audio_channel_count;
+ av8100_codec_priv->as.sampling_frequency = as->sampling_frequency;
+ av8100_codec_priv->as.sample_size = as->sample_size;
+ av8100_codec_priv->as.channel_allocation = as->channel_allocation;
+ av8100_codec_priv->as.level_shift_value = as->level_shift_value;
+ av8100_codec_priv->as.downmix_inhibit = as->downmix_inhibit;
+
return 0;
}
@@ -128,30 +202,35 @@ static int av8100_codec_pcm_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params,
struct snd_soc_dai *dai)
{
- int ret;
- int channels;
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_codec *codec = rtd->socdev->card->codec;
+ struct av8100_codec_private_data *av8100_codec_priv = codec->private_data;
pr_debug("%s: Enter.\n", __func__);
- channels = params_channels(hw_params);
- switch (channels) {
- case 1:
- goto error_channels;
- case 2:
- ret = setupAV8100_stereo();
- break;
- case 6:
- goto error_channels;
- default:
- goto error_channels;
- }
+ av8100_codec_send_audio_infoframe(&av8100_codec_priv->as);
- return ret;
+ return 0;
+}
+
+static int av8100_codec_pcm_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int ret;
+
+ pr_debug("%s: Enter.\n", __func__);
-error_channels:
- pr_err("%s: Unsupported number of channels (%d)!\n", __func__, channels);
+ /* Startup AV8100 if it is not already started */
+ ret = av8100_codec_powerup();
+ if (ret != 0) {
+ pr_err("%s: Startup of AV8100 failed "
+ "(av8100_codec_powerupAV8100 returned %d)!\n",
+ __func__,
+ ret);
+ return -EINVAL;
+ }
- return -1;
+ return 0;
}
static void av8100_codec_pcm_shutdown(struct snd_pcm_substream *substream,
@@ -172,8 +251,53 @@ static int av8100_codec_set_dai_sysclk(struct snd_soc_dai *codec_dai,
static int av8100_codec_set_dai_fmt(struct snd_soc_dai *codec_dai,
unsigned int fmt)
{
+ union av8100_configuration config;
+ int ret;
+
pr_debug("%s: Enter.\n", __func__);
+ /* Set the HDMI format of AV8100 */
+ ret = av8100_codec_setup_hdmi_format();
+ if (ret != 0)
+ return ret;
+
+ /* Set the audio input format of AV8100 */
+ config.audio_input_format.audio_input_if_format =
+ ((fmt & SND_SOC_DAIFMT_FORMAT_MASK) == SND_SOC_DAIFMT_DSP_B) ?
+ AV8100_AUDIO_TDM_MODE : AV8100_AUDIO_I2SDELAYED_MODE;
+ config.audio_input_format.audio_if_mode =
+ ((fmt & SND_SOC_DAIFMT_MASTER_MASK) == SND_SOC_DAIFMT_CBM_CFM) ?
+ AV8100_AUDIO_MASTER : AV8100_AUDIO_SLAVE;
+ pr_info("%s: Setting audio_input_format "
+ "(if_format = %d, if_mode = %d).",
+ __func__,
+ config.audio_input_format.audio_input_if_format,
+ config.audio_input_format.audio_if_mode);
+ config.audio_input_format.i2s_input_nb = 1;
+ config.audio_input_format.sample_audio_freq = AV8100_AUDIO_FREQ_48KHZ;
+ config.audio_input_format.audio_word_lg = AV8100_AUDIO_16BITS;
+ config.audio_input_format.audio_format = AV8100_AUDIO_LPCM_MODE;
+ config.audio_input_format.audio_mute = AV8100_AUDIO_MUTE_DISABLE;
+ ret = av8100_conf_prep(AV8100_COMMAND_AUDIO_INPUT_FORMAT, &config);
+ if (ret != 0) {
+ pr_err("%s: Setting audio_input_format failed "
+ "(av8100_conf_prep returned %d)!\n",
+ __func__,
+ ret);
+ return -EINVAL;
+ }
+ ret = av8100_conf_w(AV8100_COMMAND_AUDIO_INPUT_FORMAT,
+ NULL,
+ NULL,
+ I2C_INTERFACE);
+ if (ret != 0) {
+ pr_err("%s: Setting audio_input_format failed "
+ "(av8100_conf_w returned %d)!\n",
+ __func__,
+ ret);
+ return -EINVAL;
+ }
+
return 0;
}
@@ -182,15 +306,8 @@ struct snd_soc_dai av8100_codec_dai[] = {
.name = "av8100_0",
.playback = {
.stream_name = "av8100_0",
- .channels_min = 2,
- .channels_max = 6,
- .rates = AV8100_SUPPORTED_RATE,
- .formats = AV8100_SUPPORTED_FMT,
- },
- .capture = {
- .stream_name = "av8100_0",
- .channels_min = 2,
- .channels_max = 6,
+ .channels_min = 1,
+ .channels_max = 8,
.rates = AV8100_SUPPORTED_RATE,
.formats = AV8100_SUPPORTED_FMT,
},
@@ -198,6 +315,7 @@ struct snd_soc_dai av8100_codec_dai[] = {
{
.prepare = av8100_codec_pcm_prepare,
.hw_params = av8100_codec_pcm_hw_params,
+ .startup = av8100_codec_pcm_startup,
.shutdown = av8100_codec_pcm_shutdown,
.set_sysclk = av8100_codec_set_dai_sysclk,
.set_fmt = av8100_codec_set_dai_fmt,
@@ -228,6 +346,7 @@ static int av8100_codec_probe(struct platform_device *pdev)
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec;
+ struct av8100_codec_private_data *av8100_codec_priv;
int ret;
pr_info("%s: Enter (pdev = %p).\n", __func__, pdev);
@@ -244,8 +363,22 @@ static int av8100_codec_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
- mutex_init(&codec->mutex);
+ pr_info("%s: Init codec private data..\n", __func__);
+ av8100_codec_priv = kzalloc(sizeof(struct av8100_codec_private_data), GFP_KERNEL);
+ if (av8100_codec_priv == NULL)
+ return -ENOMEM;
+
+ /* Setup hdmi_audio_settings default values */
+ av8100_codec_priv->as.audio_coding_type = AV8100_CODEC_CT_IEC60958_PCM;
+ av8100_codec_priv->as.audio_channel_count = AV8100_CODEC_CC_2CH;
+ av8100_codec_priv->as.sampling_frequency = AV8100_CODEC_SF_48KHZ;
+ av8100_codec_priv->as.sample_size = AV8100_CODEC_SS_16BIT;
+ av8100_codec_priv->as.channel_allocation = AV8100_CODEC_CA_FL_FR;
+ av8100_codec_priv->as.level_shift_value = AV8100_CODEC_LSV_0DB;
+ av8100_codec_priv->as.downmix_inhibit = false;
+ codec->private_data = &av8100_codec_priv;
+ mutex_init(&codec->mutex);
socdev->card->codec = codec;
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1);
@@ -329,6 +462,4 @@ static void av8100_codec_exit(void)
module_init(av8100_codec_init);
module_exit(av8100_codec_exit);
-MODULE_DESCRIPTION("AV8100 ASoC codec driver");
-MODULE_AUTHOR("www.stericsson.com");
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/av8100_audio.h b/sound/soc/codecs/av8100_audio.h
index 6d2a7e7a801..bcd2f26ddc8 100644
--- a/sound/soc/codecs/av8100_audio.h
+++ b/sound/soc/codecs/av8100_audio.h
@@ -13,9 +13,150 @@
#ifndef AV8100_CODEC_H
#define AV8100_CODEC_H
+/* Supported sampling rates */
+#define AV8100_SUPPORTED_RATE (SNDRV_PCM_RATE_48000)
+
+/* Supported data formats */
+#define AV8100_SUPPORTED_FMT (SNDRV_PCM_FMTBIT_S16_LE)
+
+/* TDM-slot mask */
+#define AV8100_CODEC_MASK_MONO 0x0001
+#define AV8100_CODEC_MASK_STEREO 0x0005
+#define AV8100_CODEC_MASK_2DOT1 0x0015
+#define AV8100_CODEC_MASK_QUAD 0x0505
+#define AV8100_CODEC_MASK_5DOT0 0x0545
+#define AV8100_CODEC_MASK_5DOT1 0x0555
+#define AV8100_CODEC_MASK_7DOT1 0x5555
+
+enum hdmi_audio_coding_type {
+ AV8100_CODEC_CT_REFER,
+ AV8100_CODEC_CT_IEC60958_PCM,
+ AV8100_CODEC_CT_AC3,
+ AV8100_CODEC_CT_MP3,
+ AV8100_CODEC_CT_MPEG2,
+ AV8100_CODEC_CT_AAC,
+ AV8100_CODEC_CT_DTS_ATRAC,
+ AV8100_CODEC_CT_ONE_BIT_AUDIO,
+ AV8100_CODEC_CT_DOLBY_DIGITAL,
+ AV8100_CODEC_CT_DTS_HD,
+ AV8100_CODEC_CT_MAT,
+ AV8100_CODEC_CT_DTS,
+ AV8100_CODEC_CT_WMA_PRO
+};
+
+enum hdmi_audio_channel_count {
+ AV8100_CODEC_CC_REFER,
+ AV8100_CODEC_CC_2CH,
+ AV8100_CODEC_CC_3CH,
+ AV8100_CODEC_CC_4CH,
+ AV8100_CODEC_CC_5CH,
+ AV8100_CODEC_CC_6CH,
+ AV8100_CODEC_CC_7CH,
+ AV8100_CODEC_CC_8CH
+};
+
+enum hdmi_sampling_frequency {
+ AV8100_CODEC_SF_REFER,
+ AV8100_CODEC_SF_32KHZ,
+ AV8100_CODEC_SF_44_1KHZ,
+ AV8100_CODEC_SF_48KHZ,
+ AV8100_CODEC_SF_88_2KHZ,
+ AV8100_CODEC_SF_96KHZ,
+ AV8100_CODEC_SF_176_4KHZ,
+ AV8100_CODEC_SF_192KHZ
+};
+
+enum hdmi_sample_size {
+ AV8100_CODEC_SS_REFER,
+ AV8100_CODEC_SS_16BIT,
+ AV8100_CODEC_SS_20BIT,
+ AV8100_CODEC_SS_24BIT
+};
+
+enum hdmi_speaker_placement {
+ AV8100_CODEC_SP_FL, /* Front Left */
+ AV8100_CODEC_SP_FC, /* Front Center */
+ AV8100_CODEC_SP_FR, /* Front Right */
+ AV8100_CODEC_SP_FLC, /* Front Left Center */
+ AV8100_CODEC_SP_FRC, /* Front Right Center */
+ AV8100_CODEC_SP_RL, /* Rear Left */
+ AV8100_CODEC_SP_RC, /* Rear Center */
+ AV8100_CODEC_SP_RR, /* Rear Right */
+ AV8100_CODEC_SP_RLC, /* Rear Left Center */
+ AV8100_CODEC_SP_RRC, /* Rear Right Center */
+ AV8100_CODEC_SP_LFE, /* Low Frequency Effekt */
+};
+
+enum hdmi_channel_allocation {
+ AV8100_CODEC_CA_FL_FR, /* 0x00, Stereo */
+ AV8100_CODEC_CA_FL_FR_LFE, /* 0x01, 2.1 */
+ AV8100_CODEC_CA_FL_FR_FC, /* 0x02*/
+ AV8100_CODEC_CA_FL_FR_LFE_FC, /* 0x03*/
+ AV8100_CODEC_CA_FL_FR_RC, /* 0x04*/
+ AV8100_CODEC_CA_FL_FR_LFE_RC, /* 0x05*/
+ AV8100_CODEC_CA_FL_FR_FC_RC, /* 0x06*/
+ AV8100_CODEC_CA_FL_FR_LFE_FC_RC, /* 0x07*/
+ AV8100_CODEC_CA_FL_FR_RL_RR, /* 0x08, Quad */
+ AV8100_CODEC_CA_FL_FR_LFE_RL_RR, /* 0x09*/
+ AV8100_CODEC_CA_FL_FR_FC_RL_RR, /* 0x0a, 5.0*/
+ AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR, /* 0x0b, 5.1*/
+ AV8100_CODEC_CA_FL_FR_RL_RR_RC, /* 0x0c*/
+ AV8100_CODEC_CA_FL_FR_LFE_RL_RR_RC, /* 0x0d*/
+ AV8100_CODEC_CA_FL_FR_RC_RL_RR_RC, /* 0x0e*/
+ AV8100_CODEC_CA_FL_FR_LFE_RC_RL_RR_RC, /* 0x0f*/
+ AV8100_CODEC_CA_FL_FR_RL_RR_RLC_RRC, /* 0x10*/
+ AV8100_CODEC_CA_FL_FR_LFE_RL_RR_RLC_RRC, /* 0x11*/
+ AV8100_CODEC_CA_FL_FR_FC_RL_RR_RLC_RRC, /* 0x12*/
+ AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR_RLC_RRC, /* 0x13*/
+ AV8100_CODEC_CA_FL_FR_FLC_FRC, /* 0x14*/
+ AV8100_CODEC_CA_FL_FR_LFE_FLC_FRC, /* 0x15*/
+ AV8100_CODEC_CA_FL_FR_FC_FLC_FRC, /* 0x16*/
+ AV8100_CODEC_CA_FL_FR_LFE_FC_FLC_FRC, /* 0x17*/
+ AV8100_CODEC_CA_FL_FR_RC_FLC_FRC, /* 0x18*/
+ AV8100_CODEC_CA_FL_FR_LFE_RC_FLC_FRC, /* 0x19*/
+ AV8100_CODEC_CA_FL_FR_FC_RC_FLC_FRC, /* 0x1a*/
+ AV8100_CODEC_CA_FL_FR_LFE_FR_FC_RC_FLC_FRC, /* 0x1b*/
+ AV8100_CODEC_CA_FL_FR_RL_RR_FLC_FRC, /* 0x1c*/
+ AV8100_CODEC_CA_FL_FR_LFE_RL_RR_FLC_FRC, /* 0x1d*/
+ AV8100_CODEC_CA_FL_FR_FC_RL_RR_FLC_FRC, /* 0x1e*/
+ AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR_FLC_FRC /* 0x1f, 7.1 */
+};
+
+enum hdmi_level_shift_value {
+ AV8100_CODEC_LSV_0DB,
+ AV8100_CODEC_LSV_1DB,
+ AV8100_CODEC_LSV_2DB,
+ AV8100_CODEC_LSV_3DB,
+ AV8100_CODEC_LSV_4DB,
+ AV8100_CODEC_LSV_5DB,
+ AV8100_CODEC_LSV_6DB,
+ AV8100_CODEC_LSV_7DB,
+ AV8100_CODEC_LSV_8DB,
+ AV8100_CODEC_LSV_9DB,
+ AV8100_CODEC_LSV_10DB,
+ AV8100_CODEC_LSV_11DB,
+ AV8100_CODEC_LSV_12DB,
+ AV8100_CODEC_LSV_13DB,
+ AV8100_CODEC_LSV_14DB,
+ AV8100_CODEC_LSV_15DB
+};
+
+struct hdmi_audio_settings {
+ enum hdmi_audio_coding_type audio_coding_type;
+ enum hdmi_audio_channel_count audio_channel_count;
+ enum hdmi_sampling_frequency sampling_frequency;
+ enum hdmi_sample_size sample_size;
+ enum hdmi_channel_allocation channel_allocation;
+ enum hdmi_level_shift_value level_shift_value;
+ bool downmix_inhibit;
+};
+
extern struct snd_soc_dai av8100_codec_dai[];
extern struct snd_soc_codec_device soc_codec_dev_av8100;
+int av8100_codec_change_hdmi_audio_settings(struct snd_pcm_substream *substream,
+ struct hdmi_audio_settings *as);
+
#endif /* AV8100_CODEC_H */
diff --git a/sound/soc/ux500/Makefile b/sound/soc/ux500/Makefile
index 9c594d025ad..3a9091efd35 100644
--- a/sound/soc/ux500/Makefile
+++ b/sound/soc/ux500/Makefile
@@ -1,9 +1,6 @@
# Ux500 Platform Support
ifdef CONFIG_SND_SOC_UX500_DEBUG
-CFLAGS_av8100_audio.o := -DDEBUG
-CFLAGS_ab3550.o := -DDEBUG
-CFLAGS_cg29xx.o := -DDEBUG
CFLAGS_ux500_pcm.o := -DDEBUG
CFLAGS_ux500_msp_dai.o := -DDEBUG
CFLAGS_ux500_av8100.o := -DDEBUG
diff --git a/sound/soc/ux500/ux500_av8100.c b/sound/soc/ux500/ux500_av8100.c
index b6cced7f1e5..5317670c3b4 100644
--- a/sound/soc/ux500/ux500_av8100.c
+++ b/sound/soc/ux500/ux500_av8100.c
@@ -24,56 +24,139 @@
static struct platform_device *ux500_av8100_platform_device;
-static int ux500_av8100_hw_params(
- struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
+static int ux500_av8100_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
{
struct snd_soc_pcm_runtime *rtd = substream->private_data;
struct snd_soc_dai *codec_dai = rtd->dai->codec_dai;
struct snd_soc_dai *cpu_dai = rtd->dai->cpu_dai;
+
+ unsigned int tx_mask, fmt;
+ enum hdmi_channel_allocation hdmi_ca;
+ enum hdmi_audio_channel_count hdmi_cc;
+ struct hdmi_audio_settings as;
+
+ int channels = params_channels(params);
int ret = 0;
- pr_debug("%s: Enter.\n", __func__);
+ pr_debug("%s: Enter (TDM-mode, channels = %d, name = %s, number = %d).\n",
+ __func__,
+ channels,
+ substream->name,
+ substream->number);
pr_debug("%s: substream->pcm->name = %s.\n", __func__, substream->pcm->name);
pr_debug("%s: substream->pcm->id = %s.\n", __func__, substream->pcm->id);
- pr_debug("%s: substream->name = %s.\n", __func__, substream->name);
- pr_debug("%s: substream->number = %d.\n", __func__, substream->number);
-
- if (cpu_dai->ops->set_fmt) {
- dev_dbg(&ux500_av8100_platform_device->dev,
- "%s: Setting format on codec_dai: "
- "SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM.",
- __func__);
- ret = snd_soc_dai_set_fmt(
- codec_dai,
- SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- dev_dbg(&ux500_av8100_platform_device->dev,
- "%s: snd_soc_dai_set_fmt failed with %d.\n",
- __func__,
- ret);
- return ret;
- }
- dev_dbg(&ux500_av8100_platform_device->dev,
- "%s: Setting format on cpu_dai: "
- "SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM.",
- __func__);
- ret = snd_soc_dai_set_fmt(
- cpu_dai,
- SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_CBM_CFM);
- if (ret < 0) {
- dev_dbg(&ux500_av8100_platform_device->dev,
- "%s: snd_soc_dai_set_fmt failed with %d.\n",
- __func__,
- ret);
- return ret;
- }
+ switch (channels) {
+ case 1:
+ hdmi_cc = AV8100_CODEC_CC_2CH;
+ hdmi_ca = AV8100_CODEC_CA_FL_FR; /* Stereo-setup */
+ tx_mask = AV8100_CODEC_MASK_MONO;
+ break;
+ case 2:
+ hdmi_cc = AV8100_CODEC_CC_2CH;
+ hdmi_ca = AV8100_CODEC_CA_FL_FR; /* Stereo */
+ tx_mask = AV8100_CODEC_MASK_STEREO;
+ break;
+ case 3:
+ hdmi_cc = AV8100_CODEC_CC_6CH;
+ hdmi_ca = AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR; /* 5.1-setup */
+ tx_mask = AV8100_CODEC_MASK_2DOT1;
+ break;
+ case 4:
+ hdmi_cc = AV8100_CODEC_CC_6CH;
+ hdmi_ca = AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR; /* 5.1-setup */
+ tx_mask = AV8100_CODEC_MASK_QUAD;
+ break;
+ case 5:
+ hdmi_cc = AV8100_CODEC_CC_6CH;
+ hdmi_ca = AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR; /* 5.1-setup */
+ tx_mask = AV8100_CODEC_MASK_5DOT0;
+ break;
+ case 6:
+ hdmi_cc = AV8100_CODEC_CC_6CH;
+ hdmi_ca = AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR; /* 5.1 */
+ tx_mask = AV8100_CODEC_MASK_5DOT1;
+ break;
+ case 8:
+ hdmi_cc = AV8100_CODEC_CC_6CH;
+ hdmi_ca = AV8100_CODEC_CA_FL_FR_LFE_FC_RL_RR_FLC_FRC; /* 7.1 */
+ tx_mask = AV8100_CODEC_MASK_7DOT1;
+ break;
+ default:
+ pr_err("%s: Unsupported number of channels (channels = %d)!\n",
+ __func__,
+ channels);
+ return -EINVAL;
+ }
+
+ /* Change HDMI audio-settings for codec-DAI. */
+ pr_debug("%s: Change HDMI audio-settings for codec-DAI.\n", __func__);
+ as.audio_coding_type = AV8100_CODEC_CT_IEC60958_PCM;
+ as.audio_channel_count = hdmi_cc;
+ as.sampling_frequency = AV8100_CODEC_SF_48KHZ;
+ as.sample_size = AV8100_CODEC_SS_16BIT;
+ as.channel_allocation = hdmi_ca;
+ as.level_shift_value = AV8100_CODEC_LSV_0DB;
+ as.downmix_inhibit = false;
+ ret = av8100_codec_change_hdmi_audio_settings(substream, &as);
+ if (ret < 0) {
+ pr_err("%s: Unable to change HDMI audio-settings for codec-DAI "
+ "(av8100_codec_change_hdmi_audio_settings returned %d)!\n",
+ __func__,
+ ret);
+ return ret;
+ }
+
+ /* Set format for codec-DAI */
+ fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_CBM_CFM;
+ pr_debug("%s: Setting format for codec-DAI (fmt = %d).\n",
+ __func__,
+ fmt);
+ ret = snd_soc_dai_set_fmt(codec_dai, fmt);
+ if (ret < 0) {
+ pr_err("%s: Unable to set format for codec-DAI "
+ "(snd_soc_dai_set_tdm_slot returned %d)!\n",
+ __func__,
+ ret);
+ return ret;
}
- return ret;
+
+ /* Set TDM-slot for CPU-DAI */
+ pr_debug("%s: Setting TDM-slot for codec-DAI (tx_mask = %d).\n",
+ __func__,
+ tx_mask);
+ ret = snd_soc_dai_set_tdm_slot(cpu_dai, tx_mask, 0, 16, 16);
+ if (ret < 0) {
+ pr_err("%s: Unable to set TDM-slot for codec-DAI "
+ "(snd_soc_dai_set_tdm_slot returned %d)!\n",
+ __func__,
+ ret);
+ return ret;
+ }
+
+ /* Set format for CPU-DAI */
+ fmt = SND_SOC_DAIFMT_DSP_B |
+ SND_SOC_DAIFMT_CBM_CFM |
+ SND_SOC_DAIFMT_NB_IF;
+ pr_debug("%s: Setting DAI-format for Ux500-platform (fmt = %d).\n",
+ __func__,
+ fmt);
+ ret = snd_soc_dai_set_fmt(cpu_dai, fmt);
+ if (ret < 0) {
+ pr_err("%s: Unable to set DAI-format for Ux500-platform "
+ "(snd_soc_dai_set_fmt returned %d).\n",
+ __func__,
+ ret);
+ return ret;
+ }
+
+ return ret;
}
+
+
struct snd_soc_dai_link ux500_av8100_dai_links[] = {
{
.name = "hdmi",
@@ -161,4 +244,4 @@ static void __exit ux500_av8100_soc_exit(void)
module_init(ux500_av8100_soc_init);
module_exit(ux500_av8100_soc_exit);
-MODULE_LICENSE("GPL");
+MODULE_LICENSE("GPL v2");