audio: auge: add spdifin sample rate and audio type event

PD#149689: audio: auge: add spdifin sample rate and audio type event

Change-Id: I1991711ddfda438ad5c0ffa602e4364eec0737a8
Signed-off-by: Xing Wang <xing.wang@amlogic.com>
This commit is contained in:
Xing Wang
2018-04-24 16:21:44 +08:00
committed by Yixun Lan
parent 810c6dd972
commit 76cb1336a0
6 changed files with 242 additions and 34 deletions

View File

@@ -140,7 +140,18 @@ struct __extcon_info {
.id = EXTCON_JACK_SPDIF_OUT,
.name = "SPDIF-OUT",
},
#ifdef CONFIG_AMLOGIC_SND_SOC_AUGE
[EXTCON_SPDIFIN_SAMPLERATE] = {
.type = EXTCON_TYPE_MISC,
.id = EXTCON_SPDIFIN_SAMPLERATE,
.name = "SPDIFIN-SAMPLERATE",
},
[EXTCON_SPDIFIN_AUDIOTYPE] = {
.type = EXTCON_TYPE_MISC,
.id = EXTCON_SPDIFIN_AUDIOTYPE,
.name = "SPDIFIN-AUDIOTYPE",
},
#endif
/* Display external connector */
[EXTCON_DISP_HDMI] = {
.type = EXTCON_TYPE_DISP,

View File

@@ -64,7 +64,10 @@
#define EXTCON_JACK_VIDEO_OUT 25
#define EXTCON_JACK_SPDIF_IN 26 /* Sony Philips Digital InterFace */
#define EXTCON_JACK_SPDIF_OUT 27
#ifdef CONFIG_AMLOGIC_SND_SOC_AUGE
#define EXTCON_SPDIFIN_SAMPLERATE 28 /* spdif in sample rate changed */
#define EXTCON_SPDIFIN_AUDIOTYPE 29 /* spdif in PcPd detect */
#endif
/* Display external connector */
#define EXTCON_DISP_HDMI 40 /* High-Definition Multimedia Interface */
#define EXTCON_DISP_MHL 41 /* Mobile High-Definition Link */

View File

@@ -409,30 +409,6 @@ static const struct soc_enum lane3_mixer_enum =
ARRAY_SIZE(lane3_mixer_text),
lane3_mixer_text);
static const char * const spdifin_sample_rate_text[] = {
"24000",
"32000",
"44100",
"46000",
"48000",
"96000",
"192000",
};
static const struct soc_enum spdifin_sample_rate_enum =
SOC_ENUM_SINGLE_EXT(
ARRAY_SIZE(spdifin_sample_rate_text),
spdifin_sample_rate_text);
static int spdifin_sample_rate_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int mode = spdifin_get_mode();
ucontrol->value.enumerated.item[0] = mode;
return 0;
}
static const char * const spdif_channel_status_text[] = {
"Channel A Status[31:0]",
"Channel A Status[63:32]",
@@ -903,11 +879,6 @@ static const struct snd_kcontrol_new snd_auge_controls[] = {
SND_MIX("TDMOUT_C Lane3 Mixer Channel",
TDMOUT_C, lane3_mixer_enum, 23, 0x1),
/* SPDIFIN sample rate */
SOC_ENUM_EXT("SPDIFIN Sample Rate",
spdifin_sample_rate_enum,
spdifin_sample_rate_get,
NULL),
/* SPDIFIN Channel Status */
SPDIFIN_CHSTATUS("SPDIFIN Channel Status",
spdif_channel_status_enum),

View File

@@ -25,6 +25,7 @@
#include <linux/of_device.h>
#include <linux/of_platform.h>
#include <linux/clk.h>
#include <linux/extcon.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/initval.h>
@@ -75,6 +76,9 @@ struct aml_spdif {
struct toddr *tddr;
struct frddr *fddr;
/* external connect */
struct extcon_dev *edev;
unsigned int id;
struct spdif_chipinfo *chipinfo;
};
@@ -101,6 +105,172 @@ static const struct snd_pcm_hardware aml_spdif_hardware = {
.channels_max = 32,
};
static const unsigned int spdifin_extcon[] = {
EXTCON_SPDIFIN_SAMPLERATE,
EXTCON_SPDIFIN_AUDIOTYPE,
EXTCON_NONE,
};
/* current sample mode and its sample rate */
int sample_mode[] = {
24000,
32000,
44100,
46000,
48000,
96000,
192000,
};
static const char *const spdifin_samplerate[] = {
"N/A",
"24000",
"32000",
"44100",
"46000",
"48000",
"96000",
"192000"
};
static int spdifin_samplerate_get_enum(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int val = spdifin_get_sample_rate();
if (val == 0x7)
val = 0;
else
val += 1;
ucontrol->value.integer.value[0] = val;
return 0;
}
static const struct soc_enum spdifin_sample_rate_enum[] = {
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(spdifin_samplerate),
spdifin_samplerate),
};
/* spdif in audio format detect: LPCM or NONE-LPCM */
struct sppdif_audio_info {
unsigned char aud_type;
/*IEC61937 package presamble Pc value*/
short pc;
char *aud_type_str;
};
static const char *const spdif_audio_type_texts[] = {
"LPCM",
"AC3",
"EAC3",
"DTS",
"DTS-HD",
"TRUEHD",
"PAUSE"
};
static const struct sppdif_audio_info type_texts[] = {
{0, 0, "LPCM"},
{1, 0x1, "AC3"},
{2, 0x15, "EAC3"},
{3, 0xb, "DTS-I"},
{3, 0x0c, "DTS-II"},
{3, 0x0d, "DTS-III"},
{3, 0x11, "DTS-IV"},
{4, 0, "DTS-HD"},
{5, 0x16, "TRUEHD"},
{6, 0x103, "PAUSE"},
{6, 0x003, "PAUSE"},
{6, 0x100, "PAUSE"},
};
static const struct soc_enum spdif_audio_type_enum =
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, ARRAY_SIZE(spdif_audio_type_texts),
spdif_audio_type_texts);
static int spdifin_audio_type_get_enum(
struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
int audio_type = 0;
int i;
int total_num = sizeof(type_texts)/sizeof(struct sppdif_audio_info);
int pc = spdifin_get_audio_type();
for (i = 0; i < total_num; i++) {
if (pc == type_texts[i].pc) {
audio_type = type_texts[i].aud_type;
break;
}
}
ucontrol->value.enumerated.item[0] = audio_type;
return 0;
}
static const struct snd_kcontrol_new snd_spdif_controls[] = {
SOC_ENUM_EXT("SPDIFIN Sample Rate", spdifin_sample_rate_enum,
spdifin_samplerate_get_enum,
NULL),
SOC_ENUM_EXT("SPDIFIN Audio Type",
spdif_audio_type_enum,
spdifin_audio_type_get_enum,
NULL),
};
static void spdifin_status_event(struct aml_spdif *p_spdif)
{
int intrpt_status;
if (p_spdif == NULL)
return;
/*
* interrupt status, check and clear by reg_clk_interrupt;
*/
intrpt_status = aml_spdifin_status_check(p_spdif->actrl);
if (intrpt_status & 0x1)
pr_warn_once("over flow!!\n");
if (intrpt_status & 0x2)
pr_warn_once("parity error\n");
if (intrpt_status & 0x4) {
int mode = (intrpt_status >> 28) & 0x7;
pr_warn_once("sample mode changed\n");
if (mode == 0x7) {
pr_debug("Default value, not detect sample rate\n");
extcon_set_state(p_spdif->edev,
EXTCON_SPDIFIN_SAMPLERATE, 0);
} else if (mode >= 0) {
pr_debug("Event: EXTCON_SPDIFIN_SAMPLERATE, new sample rate:%d\n",
sample_mode[mode]);
extcon_set_state(p_spdif->edev,
EXTCON_SPDIFIN_SAMPLERATE, 1);
}
}
if (intrpt_status & 0x8) {
pr_warn_once("Pc changed, try to read spdifin audio type\n");
extcon_set_state(p_spdif->edev,
EXTCON_SPDIFIN_AUDIOTYPE, 1);
} else
extcon_set_state(p_spdif->edev,
EXTCON_SPDIFIN_AUDIOTYPE, 0);
if (intrpt_status & 0x10)
pr_warn_once("Pd changed\n");
if (intrpt_status & 0x20)
pr_warn_once("nonpcm to pcm\n");
if (intrpt_status & 0x40)
pr_warn_once("valid changed\n");
}
static irqreturn_t aml_spdif_ddr_isr(int irq, void *devid)
{
struct snd_pcm_substream *substream =
@@ -118,6 +288,8 @@ static irqreturn_t aml_spdifin_status_isr(int irq, void *devid)
aml_spdifin_status_check(p_spdif->actrl);
spdifin_status_event(p_spdif);
return IRQ_HANDLED;
}
@@ -160,7 +332,6 @@ static int aml_spdif_open(struct snd_pcm_substream *substream)
p_spdif->irq_spdifin);
return ret;
}
}
runtime->private_data = p_spdif;
@@ -300,6 +471,16 @@ struct snd_soc_platform_driver aml_spdif_platform = {
static int aml_dai_spdif_probe(struct snd_soc_dai *cpu_dai)
{
struct aml_spdif *p_spdif = snd_soc_dai_get_drvdata(cpu_dai);
int ret = 0;
if (p_spdif->id == SPDIF_A) {
ret = snd_soc_add_dai_controls(cpu_dai, snd_spdif_controls,
ARRAY_SIZE(snd_spdif_controls));
if (ret < 0)
pr_err("%s, failed add snd spdif controls\n", __func__);
}
pr_info("asoc debug: %s-%d\n", __func__, __LINE__);
return 0;
@@ -857,6 +1038,21 @@ static int aml_spdif_platform_probe(struct platform_device *pdev)
pr_info("%s, register soc platform\n", __func__);
/* spdifin sample rate change event */
aml_spdif->edev = devm_extcon_dev_allocate(dev, spdifin_extcon);
if (IS_ERR(aml_spdif->edev)) {
pr_err("failed to allocate spdifin extcon!!!\n");
ret = -ENOMEM;
} else {
aml_spdif->edev->dev.parent = dev;
aml_spdif->edev->name = "spdifin_event";
dev_set_name(&aml_spdif->edev->dev, "spdifin_event");
ret = extcon_dev_register(aml_spdif->edev);
if (ret < 0)
pr_err("SPDIF IN extcon failed to register!!, ignore it\n");
}
return devm_snd_soc_register_platform(dev, &aml_spdif_platform);
}

View File

@@ -55,7 +55,7 @@ void aml_spdif_arb_config(struct aml_audio_controller *actrl)
aml_audiobus_write(actrl, EE_AUDIO_ARB_CTRL, 1<<31|0xff<<0);
}
void aml_spdifin_status_check(struct aml_audio_controller *actrl)
int aml_spdifin_status_check(struct aml_audio_controller *actrl)
{
unsigned int val;
@@ -72,6 +72,8 @@ void aml_spdifin_status_check(struct aml_audio_controller *actrl)
EE_AUDIO_SPDIFIN_CTRL0,
1<<26,
0);
return val;
}
void aml_spdif_fifo_reset(
@@ -371,3 +373,24 @@ void spdifout_samesource_set(int spdif_index, int fifo_id,
} else
spdifout_clk_ctrl(spdif_id, false);
}
int spdifin_get_sample_rate(void)
{
unsigned int val;
val = audiobus_read(EE_AUDIO_SPDIFIN_STAT0);
return (val >> 28) & 0x7;
}
int spdifin_get_audio_type(void)
{
unsigned int val;
/* set ch_status_sel to read Pc*/
audiobus_update_bits(EE_AUDIO_SPDIFIN_CTRL0, 0xf << 8, 0x6 << 8);
val = audiobus_read(EE_AUDIO_SPDIFIN_STAT1);
return (val >> 16) & 0xff;
}

View File

@@ -37,7 +37,7 @@ extern void aml_spdif_enable(
extern void aml_spdif_arb_config(struct aml_audio_controller *actrl);
extern void aml_spdifin_status_check(
extern int aml_spdifin_status_check(
struct aml_audio_controller *actrl);
extern void aml_spdif_fifo_reset(
@@ -67,4 +67,8 @@ extern void spdifoutb_to_hdmitx_ctrl(int spdif_index);
extern void spdifout_samesource_set(int spdif_index, int fifo_id,
int bitwidth, bool is_enable);
extern void spdifout_enable(int spdif_id, bool is_enable);
extern int spdifin_get_sample_rate(void);
extern int spdifin_get_audio_type(void);
#endif