From 76cb1336a0d601306c6273671d51edecdbb93c29 Mon Sep 17 00:00:00 2001 From: Xing Wang Date: Tue, 24 Apr 2018 16:21:44 +0800 Subject: [PATCH] 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 --- drivers/extcon/extcon.c | 13 ++- include/linux/extcon.h | 5 +- sound/soc/amlogic/auge/audio_utils.c | 29 ----- sound/soc/amlogic/auge/spdif.c | 198 ++++++++++++++++++++++++++++++++++- sound/soc/amlogic/auge/spdif_hw.c | 25 ++++- sound/soc/amlogic/auge/spdif_hw.h | 6 +- 6 files changed, 242 insertions(+), 34 deletions(-) diff --git a/drivers/extcon/extcon.c b/drivers/extcon/extcon.c index e07ad46..b886a60 100644 --- a/drivers/extcon/extcon.c +++ b/drivers/extcon/extcon.c @@ -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, diff --git a/include/linux/extcon.h b/include/linux/extcon.h index b871c0c..190a878 100644 --- a/include/linux/extcon.h +++ b/include/linux/extcon.h @@ -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 */ diff --git a/sound/soc/amlogic/auge/audio_utils.c b/sound/soc/amlogic/auge/audio_utils.c index bc723cc..668ed08 100644 --- a/sound/soc/amlogic/auge/audio_utils.c +++ b/sound/soc/amlogic/auge/audio_utils.c @@ -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), diff --git a/sound/soc/amlogic/auge/spdif.c b/sound/soc/amlogic/auge/spdif.c index 2be6bac..46b3c74 100644 --- a/sound/soc/amlogic/auge/spdif.c +++ b/sound/soc/amlogic/auge/spdif.c @@ -25,6 +25,7 @@ #include #include #include +#include #include #include #include @@ -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); } diff --git a/sound/soc/amlogic/auge/spdif_hw.c b/sound/soc/amlogic/auge/spdif_hw.c index 017f6d7..21a11cd 100644 --- a/sound/soc/amlogic/auge/spdif_hw.c +++ b/sound/soc/amlogic/auge/spdif_hw.c @@ -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; +} diff --git a/sound/soc/amlogic/auge/spdif_hw.h b/sound/soc/amlogic/auge/spdif_hw.h index ca55acfb..dc09613 100644 --- a/sound/soc/amlogic/auge/spdif_hw.h +++ b/sound/soc/amlogic/auge/spdif_hw.h @@ -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 -- 2.7.4