From 2c8b10e48dba220548369febf1ed6767fb528173 Mon Sep 17 00:00:00 2001 From: Xing Wang Date: Wed, 16 Aug 2017 15:40:13 +0800 Subject: [PATCH] audio: snd mixer controls for tdm/spdif PD#147540: audio: add snd mixer controls for tdm/spdif 1. add gain/mute/swap/mask for tdm/spdif 2. channel status for spdif in/out 3. add loopback for s420, and fix datain channel number Change-Id: I81d4432dc2b73c7cb0275087fc3d4e23ec83e400 Signed-off-by: Xing Wang --- arch/arm64/boot/dts/amlogic/axg_s400.dts | 14 +- arch/arm64/boot/dts/amlogic/axg_s420.dts | 36 ++ sound/soc/amlogic/auge/audio_utils.c | 752 ++++++++++++++++++++++- sound/soc/amlogic/auge/audio_utils.h | 1 + sound/soc/amlogic/auge/card.c | 3 +- sound/soc/amlogic/auge/spdif_hw.c | 26 + sound/soc/amlogic/auge/spdif_hw.h | 6 + sound/soc/amlogic/auge/tdm.c | 2 +- sound/soc/codecs/amlogic/dummy_codec.c | 4 +- 9 files changed, 822 insertions(+), 22 deletions(-) diff --git a/arch/arm64/boot/dts/amlogic/axg_s400.dts b/arch/arm64/boot/dts/amlogic/axg_s400.dts index dbc182f8f05e..7acc7dd96aac 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s400.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s400.dts @@ -491,13 +491,15 @@ dai-tdm-slot-width = <32>; }; codec { + /* + * prefix-names = "3101_A", "3101_B", + * "3101_C", "3101_D"; + * sound-dai = <&tlv320adc3101_32 + * &tlv320adc3101_30 + * &tlv320adc3101_34 + * &tlv320adc3101_36>; + */ sound-dai = <&tlv320adc3101_32 &dummy_codec>; - /*prefix-names = "3101_A", "3101_B",*/ - /*"3101_C", "3101_D";*/ - /*sound-dai = <&tlv320adc3101_32*/ - /*&tlv320adc3101_30*/ - /*&tlv320adc3101_34*/ - /*&tlv320adc3101_36>;*/ }; }; diff --git a/arch/arm64/boot/dts/amlogic/axg_s420.dts b/arch/arm64/boot/dts/amlogic/axg_s420.dts index 329d5ea6f8b7..893b06545a89 100644 --- a/arch/arm64/boot/dts/amlogic/axg_s420.dts +++ b/arch/arm64/boot/dts/amlogic/axg_s420.dts @@ -342,6 +342,8 @@ aml-audio-card,name = "AML-AXGSOUND"; //aml-audio-card,mclk-fs = <256>; + aml-audio-card,loopback = <&aml_loopback>; + aml-audio-card,dai-link@0 { format = "dsp_a"; mclk-fs = <256>;//512 @@ -850,6 +852,40 @@ filter_mode = <1>; /* mode 0~4, defalut:1 */ status = "okay"; }; + + aml_loopback: loopback { + compatible = "amlogic, snd-loopback"; + /* + * 0: out rate = in data rate; + * 1: out rate = loopback data rate; + */ + lb_mode = <0>; + + /* datain src + * 0: tdmin_a; + * 1: tdmin_b; + * 2: tdmin_c; + * 3: spdifin; + * 4: pdmin; + */ + datain_src = <4>; + datain_chnum = <8>; + datain_chmask = <0xfc>; + + /* tdmin_lb src + * 0: tdmoutA + * 1: tdmoutB + * 2: tdmoutC + * 3: PAD_tdminA + * 4: PAD_tdminB + * 5: PAD_tdminC + */ + datalb_src = <1>; + datalb_chnum = <2>; + datalb_chmask = <0x3>; + + status = "okay"; + }; }; /* end of audiobus */ &pinctrl_periphs { diff --git a/sound/soc/amlogic/auge/audio_utils.c b/sound/soc/amlogic/auge/audio_utils.c index b25dc8f1bc7a..5007b89e8fa0 100644 --- a/sound/soc/amlogic/auge/audio_utils.c +++ b/sound/soc/amlogic/auge/audio_utils.c @@ -19,6 +19,14 @@ #include "regs.h" #include "iomap.h" #include "loopback_hw.h" +#include "spdif_hw.h" + +struct snd_elem_info { + struct soc_enum *ee; + int reg; + int shift; + u32 mask; +}; static unsigned int loopback_enable; @@ -56,11 +64,11 @@ static int loopback_enable_set_enum( static unsigned int loopback_datain; static const char *const loopback_datain_texts[] = { - "Tdmin A", - "Tdmin B", - "Tdmin C", - "Spdif In", - "Pdm In", + "TDMIN_A", + "TDMIN_B", + "TDMIN_C", + "SPDIFIN", + "PDMIN", }; static const struct soc_enum loopback_datain_enum = @@ -90,12 +98,12 @@ static int loopback_datain_set_enum( static unsigned int loopback_tdminlb; static const char *const loopback_tdminlb_texts[] = { - "tdmoutA", - "tdmoutB", - "tdmoutC", - "tdminA", - "tdminB", - "tdminC", + "TDMOUT_A", + "TDMOUT_B", + "TDMOUT_C", + "TDMIN_A", + "TDMIN_B", + "TDMIN_C", }; static const struct soc_enum loopback_tdminlb_enum = @@ -126,6 +134,465 @@ static int loopback_tdminlb_set_enum( return 0; } +static int snd_int_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xffffffff; + uinfo->count = 1; + + return 0; +} + +static int snd_int_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int val; + unsigned int reg = kcontrol->private_value; + + val = audiobus_read(reg); + ucontrol->value.integer.value[0] = val; + + pr_info("%s:reg:0x%x, val:0x%x\n", + __func__, + reg, + val); + + return 0; +} + +static int snd_int_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int val = (int)ucontrol->value.integer.value[0]; + unsigned int reg = kcontrol->private_value; + + pr_info("%s:reg:0x%x, val:0x%x\n", + __func__, + reg, + val); + + audiobus_write(reg, val); + + return 0; +} + +#define SND_INT(xname, type, func) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ + .name = xname, \ + .info = snd_int_info, \ + .get = snd_int_get, \ + .put = snd_int_set, \ + .private_value = EE_AUDIO_##type##_##func, \ +} + +static int snd_byte_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xff; + uinfo->count = 1; + + return 0; +} + +static int snd_byte_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int val; + struct snd_elem_info *einfo = (void *)kcontrol->private_value; + + val = audiobus_read(einfo->reg); + val >>= einfo->shift; + val &= einfo->mask; + + ucontrol->value.integer.value[0] = val; + + pr_info("%s:reg:0x%x, mask:0x%x, mask val:0x%x\n", + __func__, + einfo->reg, + einfo->mask, + val); + + return 0; +} + +static int snd_byte_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int val = (int)ucontrol->value.integer.value[0]; + struct snd_elem_info *einfo = (void *)kcontrol->private_value; + + if (val < 0) + val = 0; + if (val > 255) + val = 255; + + pr_info("%s:reg:0x%x, mask:0x%x, mask val:0x%x\n", + __func__, + einfo->reg, + einfo->mask, + val); + + audiobus_update_bits( + einfo->reg, + einfo->mask << einfo->shift, + val << einfo->shift); + + return 0; +} + +#define SND_BYTE(xname, type, func, xshift, xmask) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ + .name = xname, \ + .info = snd_byte_info, \ + .get = snd_byte_get, \ + .put = snd_byte_set, \ + .private_value = \ + ((unsigned long)&(struct snd_elem_info) \ + {.reg = EE_AUDIO_##type##_##func, \ + .shift = xshift, .mask = xmask }) \ +} + +static int snd_enum_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct snd_elem_info *einfo = (void *)kcontrol->private_value; + struct soc_enum *e = (struct soc_enum *)einfo->ee; + + return snd_ctl_enum_info(uinfo, e->shift_l == e->shift_r ? 1 : 2, + e->items, e->texts); + +} + +static int snd_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + int val; + struct snd_elem_info *einfo = (void *)kcontrol->private_value; + + val = audiobus_read(einfo->reg); + val >>= einfo->shift; + val &= einfo->mask; + ucontrol->value.integer.value[0] = val; + + pr_info("%s:reg:0x%x, mask:0x%x val:0x%x\n", + __func__, + einfo->reg, + einfo->mask, + val); + + return 0; +} + +static int snd_enum_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_elem_info *einfo = (void *)kcontrol->private_value; + int val = (int)ucontrol->value.integer.value[0]; + + pr_info("%s:reg:0x%x, swap mask:0x%x, val:0x%x\n", + __func__, + einfo->reg, + einfo->mask, + val); + + audiobus_update_bits( + einfo->reg, + einfo->mask << einfo->shift, + val << einfo->shift); + + return 0; +} + +#define SND_ENUM(xname, type, func, xenum, xshift, xmask) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ + .name = xname, \ + .info = snd_enum_info, \ + .get = snd_enum_get, \ + .put = snd_enum_set, \ + .private_value = ((unsigned long)&(struct snd_elem_info) \ + {.reg = EE_AUDIO_##type##_##func, \ + .ee = (struct soc_enum *)&xenum, \ + .shift = xshift, .mask = xmask }) \ +} + +static const char * const in_swap_channel_text[] = { + "Swap To Lane0 Left Channel", + "Swap To Lane0 Right Channel", + "Swap To Lane1 Left Channel", + "Swap To Lane1 Right Channel", + "Swap To Lane2 Left Channel", + "Swap To Lane2 Right Channel", + "Swap To Lane3 Left Channel", + "Swap To Lane3 Right Channel", +}; + +static const struct soc_enum in_swap_channel_enum = + SOC_ENUM_SINGLE_EXT( + ARRAY_SIZE(in_swap_channel_text), + in_swap_channel_text); + +static const char * const out_swap_channel_text[] = { + "Swap To CH0", + "Swap To CH1", + "Swap To CH2", + "Swap To CH3", + "Swap To CH4", + "Swap To CH5", + "Swap To CH6", + "Swap To CH7", +}; + +static const struct soc_enum out_swap_channel_enum = + SOC_ENUM_SINGLE_EXT( + ARRAY_SIZE(out_swap_channel_text), + out_swap_channel_text); + +static const char * const lane0_mixer_text[] = { + "Disable Mix", + "Lane0 Mix Left and Right Channel", +}; + +static const struct soc_enum lane0_mixer_enum = + SOC_ENUM_SINGLE_EXT( + ARRAY_SIZE(lane0_mixer_text), + lane0_mixer_text); + +static const char * const lane1_mixer_text[] = { + "Disable Mix", + "Lane1 Mix Left and Right Channel", +}; + +static const struct soc_enum lane1_mixer_enum = + SOC_ENUM_SINGLE_EXT( + ARRAY_SIZE(lane1_mixer_text), + lane1_mixer_text); + +static const char * const lane2_mixer_text[] = { + "Disable Mix", + "Lane2 Mix Left and Right Channel", +}; + +static const struct soc_enum lane2_mixer_enum = + SOC_ENUM_SINGLE_EXT( + ARRAY_SIZE(lane2_mixer_text), + lane2_mixer_text); + +static const char * const lane3_mixer_text[] = { + "Disable Mix", + "Lane3 Mix Left and Right Channel", +}; + +static const struct soc_enum lane3_mixer_enum = + SOC_ENUM_SINGLE_EXT( + 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]", + "Channel A Status[95:64]", + "Channel A Status[127:96]", + "Channel A Status[159:128]", + "Channel A Status[191:160]", + "Channel B Status[31:0]", + "Channel B Status[63:32]", + "Channel B Status[95:64]", + "Channel B Status[127:96]", + "Channel B Status[159:128]", + "Channel B Status[191:160]", +}; + +static const struct soc_enum spdif_channel_status_enum = + SOC_ENUM_SINGLE_EXT( + ARRAY_SIZE(spdif_channel_status_text), + spdif_channel_status_text); + +static int spdifin_channel_status; + +static int spdifout_channel_status; + +#define SPDIFIN_CHSTS_REG \ + EE_AUDIO_SPDIFIN_STAT1 + +#define SPDIFOUT_CHSTS_REG(xinstance) \ + (EE_AUDIO_SPDIFOUT_CHSTS0 + xinstance) + +static int spdif_channel_status_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int i; + + uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; + uinfo->value.integer.min = 0; + uinfo->value.integer.max = 0xffffffff; + uinfo->count = 1; + + for (i = 0; i < e->items; i++) + pr_info("Item:%d, %s\n", i, e->texts[i]); + + return 0; +} + +static int spdifin_channel_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int reg, status; + + pr_info("set which channel status you wanted to get firstly\n"); + reg = SPDIFIN_CHSTS_REG; + status = spdif_get_channel_status(reg); + + ucontrol->value.enumerated.item[0] = status; + + /*channel status value in printk information*/ + pr_info("%s: 0x%x\n", + e->texts[spdifin_channel_status], + status + ); + return 0; +} + +static int spdifin_channel_status_set( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int chst = ucontrol->value.enumerated.item[0]; + int ch, valid_bits; + + if (chst < 0 || chst > e->items - 1) { + pr_err("out of value, fixed it\n"); + + if (chst < 0) + chst = 0; + if (chst > e->items - 1) + chst = e->items - 1; + } + ch = (chst >= 6); + valid_bits = (chst >= 6) ? (chst - 6) : chst; + + spdifin_channel_status = chst; + pr_info("%s\n", + e->texts[spdifin_channel_status]); + + spdifin_set_channel_status(ch, valid_bits); + + return 0; +} + +static int spdifout_channel_status_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int reg, status; + + pr_info("set which channel status you wanted to get firstly\n"); + reg = SPDIFOUT_CHSTS_REG(spdifout_channel_status); + status = spdif_get_channel_status(reg); + + ucontrol->value.enumerated.item[0] = status; + + /*channel status value in printk information*/ + pr_info("%s: reg:0x%x, status:0x%x\n", + e->texts[spdifout_channel_status], + reg, + status + ); + return 0; +} + +static int spdifout_channel_status_set( + struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct soc_enum *e = (struct soc_enum *)kcontrol->private_value; + int chst = ucontrol->value.enumerated.item[0]; + + if (chst < 0 || chst > e->items - 1) { + pr_err("out of value, fixed it\n"); + + if (chst < 0) + chst = 0; + if (chst > e->items - 1) + chst = e->items - 1; + } + + spdifout_channel_status = chst; + pr_info("%s\n", + e->texts[chst]); + + return 0; +} + + +#define SPDIFIN_CHSTATUS(xname, xenum) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ + .name = xname, \ + .info = spdif_channel_status_info, \ + .get = spdifin_channel_status_get, \ + .put = spdifin_channel_status_set, \ + .private_value = (unsigned long)&xenum \ +} + +#define SPDIFOUT_CHSTATUS(xname, xenum) \ +{ \ + .iface = SNDRV_CTL_ELEM_IFACE_PCM, \ + .name = xname, \ + .info = spdif_channel_status_info, \ + .get = spdifout_channel_status_get, \ + .put = spdifout_channel_status_set, \ + .private_value = (unsigned long)&xenum\ +} + + +#define SND_MIX(xname, type, xenum, xshift, xmask) \ + SND_ENUM(xname, type, CTRL0, xenum, xshift, xmask) + +#define SND_SWAP(xname, type, xenum, xshift, xmask) \ + SND_ENUM(xname, type, SWAP, xenum, xshift, xmask) + +#define TDM_MASK(xname, type, func) \ + SND_INT(xname, type, func) + +#define TDM_MUTE(xname, type, func) \ + SND_INT(xname, type, func) + +#define TDM_GAIN(xname, type, func, xshift, xmask) \ + SND_BYTE(xname, type, func, xshift, xmask) static const struct snd_kcontrol_new snd_auge_controls[] = { /* loopback enable */ @@ -146,6 +613,267 @@ static const struct snd_kcontrol_new snd_auge_controls[] = { loopback_tdminlb_get_enum, loopback_tdminlb_set_enum), + /*TDMIN_A swap*/ + SND_SWAP("TDMIN_A Ch0 Swap", TDMIN_A, in_swap_channel_enum, 0, 0x7), + SND_SWAP("TDMIN_A Ch1 Swap", TDMIN_A, in_swap_channel_enum, 4, 0x7), + SND_SWAP("TDMIN_A Ch2 Swap", TDMIN_A, in_swap_channel_enum, 8, 0x7), + SND_SWAP("TDMIN_A Ch3 Swap", TDMIN_A, in_swap_channel_enum, 12, 0x7), + SND_SWAP("TDMIN_A Ch4 Swap", TDMIN_A, in_swap_channel_enum, 16, 0x7), + SND_SWAP("TDMIN_A Ch5 Swap", TDMIN_A, in_swap_channel_enum, 20, 0x7), + SND_SWAP("TDMIN_A Ch6 Swap", TDMIN_A, in_swap_channel_enum, 24, 0x7), + SND_SWAP("TDMIN_A Ch7 Swap", TDMIN_A, in_swap_channel_enum, 28, 0x7), + /*TDMIN_A lane0~3 mask*/ + TDM_MASK("TDMIN_A Lane0 Channel Mask", TDMIN_A, MASK0), + TDM_MASK("TDMIN_A Lane1 Channel Mask", TDMIN_A, MASK1), + TDM_MASK("TDMIN_A Lane2 Channel Mask", TDMIN_A, MASK2), + TDM_MASK("TDMIN_A Lane3 Channel Mask", TDMIN_A, MASK3), + /*TDMIN_A lane0~3 mute vale, when mute, the channel value*/ + TDM_MUTE("TDMIN_A MUTE_VAL", TDMIN_A, MUTE_VAL), + /*TDMIN_A lane0~3 mute*/ + TDM_MUTE("TDMIN_A Lane0 Mute Channel", TDMIN_A, MUTE0), + TDM_MUTE("TDMIN_A Lane1 Mute Channel", TDMIN_A, MUTE1), + TDM_MUTE("TDMIN_A Lane2 Mute Channel", TDMIN_A, MUTE2), + TDM_MUTE("TDMIN_A Lane3 Mute Channel", TDMIN_A, MUTE3), + + /*TDMIN_B swap*/ + SND_SWAP("TDMIN_B Ch0 Swap", TDMIN_B, in_swap_channel_enum, 0, 0x7), + SND_SWAP("TDMIN_B Ch1 Swap", TDMIN_B, in_swap_channel_enum, 4, 0x7), + SND_SWAP("TDMIN_B Ch2 Swap", TDMIN_B, in_swap_channel_enum, 8, 0x7), + SND_SWAP("TDMIN_B Ch3 Swap", TDMIN_B, in_swap_channel_enum, 12, 0x7), + SND_SWAP("TDMIN_B Ch4 Swap", TDMIN_B, in_swap_channel_enum, 16, 0x7), + SND_SWAP("TDMIN_B Ch5 Swap", TDMIN_B, in_swap_channel_enum, 20, 0x7), + SND_SWAP("TDMIN_B Ch6 Swap", TDMIN_B, in_swap_channel_enum, 24, 0x7), + SND_SWAP("TDMIN_B Ch7 Swap", TDMIN_B, in_swap_channel_enum, 28, 0x7), + /*TDMIN_B lane0~3 mask*/ + TDM_MASK("TDMIN_B Lane0 Channel Mask", TDMIN_B, MASK0), + TDM_MASK("TDMIN_B Lane1 Channel Mask", TDMIN_B, MASK1), + TDM_MASK("TDMIN_B Lane2 Channel Mask", TDMIN_B, MASK2), + TDM_MASK("TDMIN_B Lane3 Channel Mask", TDMIN_B, MASK3), + /*TDMIN_B lane0~3 mute vale*/ + TDM_MUTE("TDMIN_B MUTE_VAL", TDMIN_B, MUTE_VAL), + /*TDMIN_B lane0~3 mute*/ + TDM_MUTE("TDMIN_B Lane0 Mute Channel", TDMIN_B, MUTE0), + TDM_MUTE("TDMIN_B Lane1 Mute Channel", TDMIN_B, MUTE1), + TDM_MUTE("TDMIN_B Lane2 Mute Channel", TDMIN_B, MUTE2), + TDM_MUTE("TDMIN_B Lane3 Mute Channel", TDMIN_B, MUTE3), + + /*TDMIN_C swap*/ + SND_SWAP("TDMIN_C Ch0 Swap", TDMIN_C, in_swap_channel_enum, 0, 0x7), + SND_SWAP("TDMIN_C Ch1 Swap", TDMIN_C, in_swap_channel_enum, 4, 0x7), + SND_SWAP("TDMIN_C Ch2 Swap", TDMIN_C, in_swap_channel_enum, 8, 0x7), + SND_SWAP("TDMIN_C Ch3 Swap", TDMIN_C, in_swap_channel_enum, 12, 0x7), + SND_SWAP("TDMIN_C Ch4 Swap", TDMIN_C, in_swap_channel_enum, 16, 0x7), + SND_SWAP("TDMIN_C Ch5 Swap", TDMIN_C, in_swap_channel_enum, 20, 0x7), + SND_SWAP("TDMIN_C Ch6 Swap", TDMIN_C, in_swap_channel_enum, 24, 0x7), + SND_SWAP("TDMIN_C Ch7 Swap", TDMIN_C, in_swap_channel_enum, 28, 0x7), + /*TDMIN_C lane0~3 mask*/ + TDM_MASK("TDMIN_C Lane0 Channel Mask", TDMIN_C, MASK0), + TDM_MASK("TDMIN_C Lane1 Channel Mask", TDMIN_C, MASK1), + TDM_MASK("TDMIN_C Lane2 Channel Mask", TDMIN_C, MASK2), + TDM_MASK("TDMIN_C Lane3 Channel Mask", TDMIN_C, MASK3), + /*TDMIN_C lane0~3 mute vale*/ + TDM_MUTE("TDMIN_C MUTE_VAL", TDMIN_C, MUTE_VAL), + /*TDMIN_C lane0~3 mute*/ + TDM_MUTE("TDMIN_C Lane0 Mute Channel", TDMIN_C, MUTE0), + TDM_MUTE("TDMIN_C Lane1 Mute Channel", TDMIN_C, MUTE1), + TDM_MUTE("TDMIN_C Lane2 Mute Channel", TDMIN_C, MUTE2), + TDM_MUTE("TDMIN_C Lane3 Mute Channel", TDMIN_C, MUTE3), + + /*TDMIN_LB swap*/ + SND_SWAP("TDMIN_LB Ch0 Swap", TDMIN_LB, in_swap_channel_enum, 0, 0x7), + SND_SWAP("TDMIN_LB Ch1 Swap", TDMIN_LB, in_swap_channel_enum, 4, 0x7), + SND_SWAP("TDMIN_LB Ch2 Swap", TDMIN_LB, in_swap_channel_enum, 8, 0x7), + SND_SWAP("TDMIN_LB Ch3 Swap", TDMIN_LB, in_swap_channel_enum, 12, 0x7), + SND_SWAP("TDMIN_LB Ch4 Swap", TDMIN_LB, in_swap_channel_enum, 16, 0x7), + SND_SWAP("TDMIN_LB Ch5 Swap", TDMIN_LB, in_swap_channel_enum, 20, 0x7), + SND_SWAP("TDMIN_LB Ch6 Swap", TDMIN_LB, in_swap_channel_enum, 24, 0x7), + SND_SWAP("TDMIN_LB Ch7 Swap", TDMIN_LB, in_swap_channel_enum, 28, 0x7), + /*TDMIN_LB lane0~3 mask*/ + TDM_MASK("TDMIN_LB Lane0 Channel Mask", TDMIN_LB, MASK0), + TDM_MASK("TDMIN_LB Lane1 Channel Mask", TDMIN_LB, MASK1), + TDM_MASK("TDMIN_LB Lane2 Channel Mask", TDMIN_LB, MASK2), + TDM_MASK("TDMIN_LB Lane3 Channel Mask", TDMIN_LB, MASK3), + /*TDMIN_LB lane0~3 mute vale*/ + TDM_MUTE("TDMIN_LB MUTE_VAL", TDMIN_LB, MUTE_VAL), + /*TDMIN_LB lane0~3 mute*/ + TDM_MUTE("TDMIN_LB Lane0 Mute Channel", TDMIN_LB, MUTE0), + TDM_MUTE("TDMIN_LB Lane1 Mute Channel", TDMIN_LB, MUTE1), + TDM_MUTE("TDMIN_LB Lane2 Mute Channel", TDMIN_LB, MUTE2), + TDM_MUTE("TDMIN_LB Lane3 Mute Channel", TDMIN_LB, MUTE3), + + /*TDMOUT_A swap*/ + SND_SWAP("TDMOUT_A Lane0 Left Channel Swap", + TDMOUT_A, out_swap_channel_enum, 0, 0x7), + SND_SWAP("TDMOUT_A Lane0 Right Channel Swap", + TDMOUT_A, out_swap_channel_enum, 4, 0x7), + SND_SWAP("TDMOUT_A Lane1 Left Channel Swap", + TDMOUT_A, out_swap_channel_enum, 8, 0x7), + SND_SWAP("TDMOUT_A Lane1 Right Channel Swap", + TDMOUT_A, out_swap_channel_enum, 12, 0x7), + SND_SWAP("TDMOUT_A Lane2 Left Channel Swap", + TDMOUT_A, out_swap_channel_enum, 16, 0x7), + SND_SWAP("TDMOUT_A Lane2 Right Channel Swap", + TDMOUT_A, out_swap_channel_enum, 20, 0x7), + SND_SWAP("TDMOUT_A Lane3 Left Channel Swap", + TDMOUT_A, out_swap_channel_enum, 24, 0x7), + SND_SWAP("TDMOUT_A Lane3 Right Channel Swap", + TDMOUT_A, out_swap_channel_enum, 28, 0x7), + /*TDMOUT_A mask value*/ + TDM_MASK("TDMOUT_A Lane0 MASK_VAL", TDMOUT_A, MASK_VAL), + /*TDMOUT_A lane0~3 mask*/ + TDM_MASK("TDMOUT_A Lane0 Channel Mask", TDMOUT_A, MASK0), + TDM_MASK("TDMOUT_A Lane1 Channel Mask", TDMOUT_A, MASK1), + TDM_MASK("TDMOUT_A Lane2 Channel Mask", TDMOUT_A, MASK2), + TDM_MASK("TDMOUT_A Lane3 Channel Mask", TDMOUT_A, MASK3), + /*TDMOUT_A gain, enable data * gain*/ + TDM_GAIN("TDMOUT_A GAIN Enable", TDMOUT_A, CTRL1, 26, 0x1), + TDM_GAIN("TDMOUT_A GAIN CH0", TDMOUT_A, GAIN0, 0, 0xff), + TDM_GAIN("TDMOUT_A GAIN CH1", TDMOUT_A, GAIN0, 8, 0xff), + TDM_GAIN("TDMOUT_A GAIN CH2", TDMOUT_A, GAIN0, 16, 0xff), + TDM_GAIN("TDMOUT_A GAIN CH3", TDMOUT_A, GAIN0, 24, 0xff), + TDM_GAIN("TDMOUT_A GAIN CH4", TDMOUT_A, GAIN1, 0, 0xff), + TDM_GAIN("TDMOUT_A GAIN CH5", TDMOUT_A, GAIN1, 8, 0xff), + TDM_GAIN("TDMOUT_A GAIN CH6", TDMOUT_A, GAIN1, 16, 0xff), + TDM_GAIN("TDMOUT_A GAIN CH7", TDMOUT_A, GAIN1, 24, 0xff), + /*TDMOUT_A lane0~3 mute vale*/ + TDM_MUTE("TDMOUT_A MUTE_VAL", TDMOUT_A, MUTE_VAL), + /*TDMOUT_A lane0~3 mute*/ + TDM_MUTE("TDMOUT_A Lane0 Mute Channel", TDMOUT_A, MUTE0), + TDM_MUTE("TDMOUT_A Lane1 Mute Channel", TDMOUT_A, MUTE1), + TDM_MUTE("TDMOUT_A Lane2 Mute Channel", TDMOUT_A, MUTE2), + TDM_MUTE("TDMOUT_A Lane3 Mute Channel", TDMOUT_A, MUTE3), + /*TDMOUT_A lane0~3 mixer*/ + SND_MIX("TDMOUT_A Lane0 Mixer Channel", + TDMOUT_A, lane0_mixer_enum, 20, 0x1), + SND_MIX("TDMOUT_A Lane1 Mixer Channel", + TDMOUT_A, lane1_mixer_enum, 21, 0x1), + SND_MIX("TDMOUT_A Lane2 Mixer Channel", + TDMOUT_A, lane2_mixer_enum, 22, 0x1), + SND_MIX("TDMOUT_A Lane3 Mixer Channel", + TDMOUT_A, lane3_mixer_enum, 23, 0x1), + + /*TDMOUT_B swap*/ + SND_SWAP("TDMOUT_B Lane0 Left Channel Swap", + TDMOUT_B, out_swap_channel_enum, 0, 0x7), + SND_SWAP("TDMOUT_B Lane0 Right Channel Swap", + TDMOUT_B, out_swap_channel_enum, 4, 0x7), + SND_SWAP("TDMOUT_B Lane1 Left Channel Swap", + TDMOUT_B, out_swap_channel_enum, 8, 0x7), + SND_SWAP("TDMOUT_B Lane1 Right Channel Swap", + TDMOUT_B, out_swap_channel_enum, 12, 0x7), + SND_SWAP("TDMOUT_B Lane2 Left Channel Swap", + TDMOUT_B, out_swap_channel_enum, 16, 0x7), + SND_SWAP("TDMOUT_B Lane2 Right Channel Swap", + TDMOUT_B, out_swap_channel_enum, 20, 0x7), + SND_SWAP("TDMOUT_B Lane3 Left Channel Swap", + TDMOUT_B, out_swap_channel_enum, 24, 0x7), + SND_SWAP("TDMOUT_B Lane3 Right Channel Swap", + TDMOUT_B, out_swap_channel_enum, 28, 0x7), + /*TDMOUT_B mask value*/ + TDM_MASK("TDMOUT_B Lane0 MASK_VAL", TDMOUT_B, MASK_VAL), + /*TDMOUT_B lane0~3 mask*/ + TDM_MASK("TDMOUT_B Lane0 Channel Mask", TDMOUT_B, MASK0), + TDM_MASK("TDMOUT_B Lane1 Channel Mask", TDMOUT_B, MASK1), + TDM_MASK("TDMOUT_B Lane2 Channel Mask", TDMOUT_B, MASK2), + TDM_MASK("TDMOUT_B Lane3 Channel Mask", TDMOUT_B, MASK3), + /*TDMOUT_B gain, enable data * gain*/ + TDM_GAIN("TDMOUT_B GAIN Enable", TDMOUT_B, CTRL1, 26, 0x1), + TDM_GAIN("TDMOUT_B GAIN CH0", TDMOUT_B, GAIN0, 0, 0xff), + TDM_GAIN("TDMOUT_B GAIN CH1", TDMOUT_B, GAIN0, 8, 0xff), + TDM_GAIN("TDMOUT_B GAIN CH2", TDMOUT_B, GAIN0, 16, 0xff), + TDM_GAIN("TDMOUT_B GAIN CH3", TDMOUT_B, GAIN0, 24, 0xff), + TDM_GAIN("TDMOUT_B GAIN CH4", TDMOUT_B, GAIN1, 0, 0xff), + TDM_GAIN("TDMOUT_B GAIN CH5", TDMOUT_B, GAIN1, 8, 0xff), + TDM_GAIN("TDMOUT_B GAIN CH6", TDMOUT_B, GAIN1, 16, 0xff), + TDM_GAIN("TDMOUT_B GAIN CH7", TDMOUT_B, GAIN1, 24, 0xff), + /*TDMOUT_B lane0~3 mute vale*/ + TDM_MUTE("TDMOUT_B MUTE_VAL", TDMOUT_B, MUTE_VAL), + /*TDMOUT_B lane0~3 mute*/ + TDM_MUTE("TDMOUT_B Lane0 Mute Channel", TDMOUT_B, MUTE0), + TDM_MUTE("TDMOUT_B Lane1 Mute Channel", TDMOUT_B, MUTE1), + TDM_MUTE("TDMOUT_B Lane2 Mute Channel", TDMOUT_B, MUTE2), + TDM_MUTE("TDMOUT_B Lane3 Mute Channel", TDMOUT_B, MUTE3), + /*TDMOUT_B lane0~3 mixer*/ + SND_MIX("TDMOUT_B Lane0 Mixer Channel", + TDMOUT_B, lane0_mixer_enum, 20, 0x1), + SND_MIX("TDMOUT_B Lane1 Mixer Channel", + TDMOUT_B, lane1_mixer_enum, 21, 0x1), + SND_MIX("TDMOUT_B Lane2 Mixer Channel", + TDMOUT_B, lane2_mixer_enum, 22, 0x1), + SND_MIX("TDMOUT_B Lane3 Mixer Channel", + TDMOUT_B, lane3_mixer_enum, 23, 0x1), + + /*TDMOUT_C swap*/ + SND_SWAP("TDMOUT_C Lane0 Left Channel Swap", + TDMOUT_C, out_swap_channel_enum, 0, 0x7), + SND_SWAP("TDMOUT_C Lane0 Right Channel Swap", + TDMOUT_C, out_swap_channel_enum, 4, 0x7), + SND_SWAP("TDMOUT_C Lane1 Left Channel Swap", + TDMOUT_C, out_swap_channel_enum, 8, 0x7), + SND_SWAP("TDMOUT_C Lane1 Right Channel Swap", + TDMOUT_C, out_swap_channel_enum, 12, 0x7), + SND_SWAP("TDMOUT_C Lane2 Left Channel Swap", + TDMOUT_C, out_swap_channel_enum, 16, 0x7), + SND_SWAP("TDMOUT_C Lane2 Right Channel Swap", + TDMOUT_C, out_swap_channel_enum, 20, 0x7), + SND_SWAP("TDMOUT_C Lane3 Left Channel Swap", + TDMOUT_C, out_swap_channel_enum, 24, 0x7), + SND_SWAP("TDMOUT_C Lane3 Right Channel Swap", + TDMOUT_C, out_swap_channel_enum, 28, 0x7), + /*TDMOUT_C mask value*/ + TDM_MASK("TDMOUT_C Lane0 MASK_VAL", TDMOUT_C, MASK_VAL), + /*TDMOUT_C lane0~3 mask*/ + TDM_MASK("TDMOUT_C Lane0 Channel Mask", TDMOUT_C, MASK0), + TDM_MASK("TDMOUT_C Lane1 Channel Mask", TDMOUT_C, MASK1), + TDM_MASK("TDMOUT_C Lane2 Channel Mask", TDMOUT_C, MASK2), + TDM_MASK("TDMOUT_C Lane3 Channel Mask", TDMOUT_C, MASK3), + /*TDMOUT_C gain, enable data * gain*/ + TDM_GAIN("TDMOUT_C GAIN Enable", TDMOUT_C, CTRL1, 26, 0x1), + TDM_GAIN("TDMOUT_C GAIN CH0", TDMOUT_C, GAIN0, 0, 0xff), + TDM_GAIN("TDMOUT_C GAIN CH1", TDMOUT_C, GAIN0, 8, 0xff), + TDM_GAIN("TDMOUT_C GAIN CH2", TDMOUT_C, GAIN0, 16, 0xff), + TDM_GAIN("TDMOUT_C GAIN CH3", TDMOUT_C, GAIN0, 24, 0xff), + TDM_GAIN("TDMOUT_C GAIN CH4", TDMOUT_C, GAIN1, 0, 0xff), + TDM_GAIN("TDMOUT_C GAIN CH5", TDMOUT_C, GAIN1, 8, 0xff), + TDM_GAIN("TDMOUT_C GAIN CH6", TDMOUT_C, GAIN1, 16, 0xff), + TDM_GAIN("TDMOUT_C GAIN CH7", TDMOUT_C, GAIN1, 24, 0xff), + /*TDMOUT_C lane0~3 mute vale*/ + TDM_MUTE("TDMOUT_C MUTE_VAL", TDMOUT_C, MUTE_VAL), + /*TDMOUT_C lane0~3 mute*/ + TDM_MUTE("TDMOUT_C Lane0 Mute Channel", TDMOUT_C, MUTE0), + TDM_MUTE("TDMOUT_C Lane1 Mute Channel", TDMOUT_C, MUTE1), + TDM_MUTE("TDMOUT_C Lane2 Mute Channel", TDMOUT_C, MUTE2), + TDM_MUTE("TDMOUT_C Lane3 Mute Channel", TDMOUT_C, MUTE3), + /*TDMOUT_C lane0~3 mixer*/ + SND_MIX("TDMOUT_C Lane0 Mixer Channel", + TDMOUT_C, lane0_mixer_enum, 20, 0x1), + SND_MIX("TDMOUT_C Lane1 Mixer Channel", + TDMOUT_C, lane1_mixer_enum, 21, 0x1), + SND_MIX("TDMOUT_C Lane2 Mixer Channel", + TDMOUT_C, lane2_mixer_enum, 22, 0x1), + 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), + + /*SPDIFOUT swap*/ + SND_SWAP("SPDIFOUT Lane0 Left Channel Swap", + SPDIFOUT, out_swap_channel_enum, 0, 0x7), + SND_SWAP("SPDIFOUT Lane0 Right Channel Swap", + SPDIFOUT, out_swap_channel_enum, 4, 0x7), + /*SPDIFOUT mixer*/ + SND_MIX("SPDIFOUT Mixer Channel", + SPDIFOUT, lane0_mixer_enum, 23, 0x1), + /* SPDIFIN Channel Status */ + SPDIFOUT_CHSTATUS("SPDIFOUT Channel Status", + spdif_channel_status_enum), }; @@ -299,7 +1027,7 @@ int loopback_prepare( } datain_cfg.ext_signed = 0; - datain_cfg.chnum = runtime->channels; + datain_cfg.chnum = lb_cfg->datain_chnum; datain_cfg.chmask = lb_cfg->datain_chmask; ddrdata.combined_type = datain_toddr_type; ddrdata.msb = datain_msb; diff --git a/sound/soc/amlogic/auge/audio_utils.h b/sound/soc/amlogic/auge/audio_utils.h index 04a012493494..c85823f46414 100644 --- a/sound/soc/amlogic/auge/audio_utils.h +++ b/sound/soc/amlogic/auge/audio_utils.h @@ -20,6 +20,7 @@ #include #include +#include /* datain src * [4]: pdmin; diff --git a/sound/soc/amlogic/auge/card.c b/sound/soc/amlogic/auge/card.c index 5aa494b22e1a..6af38e975aae 100644 --- a/sound/soc/amlogic/auge/card.c +++ b/sound/soc/amlogic/auge/card.c @@ -223,7 +223,8 @@ int aml_card_prepare(struct snd_pcm_substream *substream) struct snd_soc_pcm_runtime *rtd = substream->private_data; struct aml_card_data *priv = snd_soc_card_get_drvdata(rtd->card); - loopback_prepare(substream, &priv->lb_cfg); + if (loopback_is_enable()) + loopback_prepare(substream, &priv->lb_cfg); return 0; } diff --git a/sound/soc/amlogic/auge/spdif_hw.c b/sound/soc/amlogic/auge/spdif_hw.c index cb8719bc5201..84477f45a5a7 100644 --- a/sound/soc/amlogic/auge/spdif_hw.c +++ b/sound/soc/amlogic/auge/spdif_hw.c @@ -17,6 +17,7 @@ #include +#include "iomap.h" #include "spdif_hw.h" void aml_spdif_enable( @@ -175,3 +176,28 @@ void aml_spdif_fifo_ctrl( } } + +int spdifin_get_mode(void) +{ + int mode_val = audiobus_read(EE_AUDIO_SPDIFIN_STAT0); + + mode_val >>= 28; + mode_val &= 0x7; + + return mode_val; +} + +int spdif_get_channel_status(int reg) +{ + return audiobus_read(reg); +} + +void spdifin_set_channel_status(int ch, int bits) +{ + int ch_status_sel = (ch << 3 | bits) & 0xf; + + /*which channel status would be got*/ + audiobus_update_bits(EE_AUDIO_SPDIFIN_CTRL0, + 0xf << 8, + ch_status_sel << 8); +} diff --git a/sound/soc/amlogic/auge/spdif_hw.h b/sound/soc/amlogic/auge/spdif_hw.h index 696483f7473f..3e7fc802dc33 100644 --- a/sound/soc/amlogic/auge/spdif_hw.h +++ b/sound/soc/amlogic/auge/spdif_hw.h @@ -38,4 +38,10 @@ extern void aml_spdif_fifo_ctrl( struct aml_audio_controller *actrl, int bitwidth, int stream); + +extern int spdifin_get_mode(void); + +extern int spdif_get_channel_status(int reg); + +extern void spdifin_set_channel_status(int ch, int bits); #endif diff --git a/sound/soc/amlogic/auge/tdm.c b/sound/soc/amlogic/auge/tdm.c index 731c32707f2f..20a1f0b5dd7c 100644 --- a/sound/soc/amlogic/auge/tdm.c +++ b/sound/soc/amlogic/auge/tdm.c @@ -101,7 +101,7 @@ static const struct snd_pcm_hardware aml_tdm_hardware = { .rate_min = 8000, .rate_max = 48000, - .channels_min = 2, + .channels_min = 1, .channels_max = 32, }; diff --git a/sound/soc/codecs/amlogic/dummy_codec.c b/sound/soc/codecs/amlogic/dummy_codec.c index ddc83200090d..4444a3f6f8e6 100644 --- a/sound/soc/codecs/amlogic/dummy_codec.c +++ b/sound/soc/codecs/amlogic/dummy_codec.c @@ -84,14 +84,14 @@ struct snd_soc_dai_driver dummy_codec_dai = { .playback = { .stream_name = "HIFI Playback", .channels_min = 1, - .channels_max = 8, + .channels_max = 32, .rates = DUMMY_CODEC_RATES, .formats = DUMMY_CODEC_FORMATS, }, .capture = { .stream_name = "HIFI Capture", .channels_min = 1, - .channels_max = 8, + .channels_max = 32, .rates = DUMMY_CODEC_RATES, .formats = DUMMY_CODEC_FORMATS, },