blob: 87d8619d6fd40430f8f37ea090202eb3bdc53f0a [file] [log] [blame]
/*
* sound/soc/amlogic/common/spdif_info.c
*
* Copyright (C) 2018 Amlogic, Inc. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#define DEBUG
#undef pr_fmt
#define pr_fmt(fmt) "spdif_info: " fmt
#include <linux/amlogic/media/sound/aout_notify.h>
#include <linux/amlogic/media/sound/spdif_info.h>
#ifdef CONFIG_AMLOGIC_HDMITX
#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_ext.h>
#endif
/*
* 0 -- other formats except(DD,DD+,DTS)
* 1 -- DTS
* 2 -- DD
* 3 -- DTS with 958 PCM RAW package mode
* 4 -- DD+
*/
unsigned int IEC958_mode_codec;
EXPORT_SYMBOL(IEC958_mode_codec);
bool spdif_is_4x_clk(void)
{
bool is_4x = false;
if (IEC958_mode_codec == 4 || IEC958_mode_codec == 5 ||
IEC958_mode_codec == 7 || IEC958_mode_codec == 8) {
is_4x = true;
}
return is_4x;
}
void spdif_get_channel_status_info(
struct iec958_chsts *chsts,
unsigned int rate)
{
int rate_bit = snd_pcm_rate_to_rate_bit(rate);
if (rate_bit == SNDRV_PCM_RATE_KNOT) {
pr_err("Unsupport sample rate\n");
return;
}
if (IEC958_mode_codec && IEC958_mode_codec != 9) {
if (IEC958_mode_codec == 1) {
/* dts, use raw sync-word mode */
pr_info("iec958 mode RAW\n");
} else {
/* ac3,use the same pcm mode as i2s */
}
chsts->chstat0_l = 0x1902;
chsts->chstat0_r = 0x1902;
if (IEC958_mode_codec == 4 || IEC958_mode_codec == 5) {
/* DD+ */
if (rate_bit == SNDRV_PCM_RATE_32000) {
chsts->chstat1_l = 0x300;
chsts->chstat1_r = 0x300;
} else if (rate_bit == SNDRV_PCM_RATE_44100) {
chsts->chstat1_l = 0xc00;
chsts->chstat1_r = 0xc00;
} else {
chsts->chstat1_l = 0Xe00;
chsts->chstat1_r = 0Xe00;
}
} else {
/* DTS,DD */
if (rate_bit == SNDRV_PCM_RATE_32000) {
chsts->chstat1_l = 0x300;
chsts->chstat1_r = 0x300;
} else if (rate_bit == SNDRV_PCM_RATE_44100) {
chsts->chstat1_l = 0;
chsts->chstat1_r = 0;
} else {
chsts->chstat1_l = 0x200;
chsts->chstat1_r = 0x200;
}
}
} else {
chsts->chstat0_l = 0x0100;
chsts->chstat0_r = 0x0100;
chsts->chstat1_l = 0x200;
chsts->chstat1_r = 0x200;
if (rate_bit == SNDRV_PCM_RATE_44100) {
chsts->chstat1_l = 0;
chsts->chstat1_r = 0;
} else if (rate_bit == SNDRV_PCM_RATE_88200) {
chsts->chstat1_l = 0x800;
chsts->chstat1_r = 0x800;
} else if (rate_bit == SNDRV_PCM_RATE_96000) {
chsts->chstat1_l = 0xa00;
chsts->chstat1_r = 0xa00;
} else if (rate_bit == SNDRV_PCM_RATE_176400) {
chsts->chstat1_l = 0xc00;
chsts->chstat1_r = 0xc00;
} else if (rate_bit == SNDRV_PCM_RATE_192000) {
chsts->chstat1_l = 0xe00;
chsts->chstat1_r = 0xe00;
}
}
pr_debug("rate: %d, channel status ch0_l:0x%x, ch0_r:0x%x, ch1_l:0x%x, ch1_r:0x%x\n",
rate,
chsts->chstat0_l,
chsts->chstat0_r,
chsts->chstat1_l,
chsts->chstat1_r);
}
void spdif_notify_to_hdmitx(struct snd_pcm_substream *substream)
{
if (IEC958_mode_codec == 2) {
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_AC_3,
substream);
} else if (IEC958_mode_codec == 3) {
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_DTS,
substream);
} else if (IEC958_mode_codec == 4) {
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_DOBLY_DIGITAL_PLUS,
substream);
} else if (IEC958_mode_codec == 5) {
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_DTS_HD,
substream);
} else if (IEC958_mode_codec == 7 ||
IEC958_mode_codec == 8) {
//aml_aiu_write(AIU_958_CHSTAT_L0, 0x1902);
//aml_aiu_write(AIU_958_CHSTAT_L1, 0x900);
//aml_aiu_write(AIU_958_CHSTAT_R0, 0x1902);
//aml_aiu_write(AIU_958_CHSTAT_R1, 0x900);
if (IEC958_mode_codec == 8)
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_DTS_HD_MA,
substream);
else
aout_notifier_call_chain(
AOUT_EVENT_RAWDATA_MAT_MLP,
substream);
} else {
aout_notifier_call_chain(
AOUT_EVENT_IEC_60958_PCM,
substream);
}
}
static const char *const spdif_format_texts[10] = {
"2 CH PCM", "DTS RAW Mode", "Dolby Digital", "DTS",
"DD+", "DTS-HD", "Multi-channel LPCM", "TrueHD", "DTS-HD MA",
"HIGH SR Stereo LPCM"
};
const struct soc_enum spdif_format_enum =
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(spdif_format_texts),
spdif_format_texts);
int spdif_format_get_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.enumerated.item[0] = IEC958_mode_codec;
return 0;
}
int spdif_format_set_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int index = ucontrol->value.enumerated.item[0];
if (index >= 10) {
pr_err("bad parameter for spdif format set\n");
return -1;
}
IEC958_mode_codec = index;
return 0;
}
#ifdef CONFIG_AMLOGIC_HDMITX
unsigned int aml_audio_hdmiout_mute_flag;
/* call HDMITX API to enable/disable internal audio out */
int aml_get_hdmi_out_audio(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
ucontrol->value.integer.value[0] = !hdmitx_ext_get_audio_status();
aml_audio_hdmiout_mute_flag =
ucontrol->value.integer.value[0];
return 0;
}
int aml_set_hdmi_out_audio(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
bool mute = ucontrol->value.integer.value[0];
if (aml_audio_hdmiout_mute_flag != mute) {
hdmitx_ext_set_audio_output(!mute);
aml_audio_hdmiout_mute_flag = mute;
}
return 0;
}
#endif