From dfb47d5d7561d0fb735603353790224c0f640328 Mon Sep 17 00:00:00 2001 From: Ola Lilja Date: Fri, 1 Oct 2010 16:06:57 +0200 Subject: 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 Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/5915 Reviewed-by: Linus WALLEIJ --- sound/soc/codecs/Makefile | 5 + sound/soc/codecs/av8100_audio.c | 245 ++++++++++++++++++++++++++++++---------- sound/soc/codecs/av8100_audio.h | 141 +++++++++++++++++++++++ sound/soc/ux500/Makefile | 3 - sound/soc/ux500/ux500_av8100.c | 159 +++++++++++++++++++------- 5 files changed, 455 insertions(+), 98 deletions(-) (limited to 'sound') diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index 65f9a79d8c6..662c6b899e5 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -211,3 +211,8 @@ obj-$(CONFIG_SND_SOC_WM_HUBS) += snd-soc-wm-hubs.o # Amp obj-$(CONFIG_SND_SOC_MAX9877) += snd-soc-max9877.o obj-$(CONFIG_SND_SOC_TPA6130A2) += snd-soc-tpa6130a2.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"); -- cgit v1.2.3