audio: add an interface for HDMI out disable [1/2]
authorqi.yuan <qi.yuan@amlogic.com>
Fri, 20 Apr 2018 11:08:29 +0000 (19:08 +0800)
committerYixun Lan <yixun.lan@amlogic.com>
Thu, 10 May 2018 05:23:33 +0000 (22:23 -0700)
PD#165284: add an interface control for audio hdmi out disable

1)add a gpio control switch for ARCIN and SPDIFIN
2)clean global value in audio driver
3)rewrite HDMITX audio control interface
4)remove HDMITX user space control SYSFS
  Forbidden user space control of HDMITX audio, must via AUDIO

Change-Id: Ifc69c8553df903631d80f414771d91966045f85f
Signed-off-by: qi.yuan <qi.yuan@amlogic.com>
Signed-off-by: Zongdong Jiao <zongdong.jiao@amlogic.com>
Signed-off-by: Zhe Wang <Zhe.Wang@amlogic.com>
arch/arm64/boot/dts/amlogic/txlx_t962e_r321.dts
arch/arm64/boot/dts/amlogic/txlx_t962x_r311_1g.dts
arch/arm64/boot/dts/amlogic/txlx_t962x_r311_2g.dts
arch/arm64/boot/dts/amlogic/txlx_t962x_r311_720p.dts
drivers/amlogic/media/vout/hdmitx/hdmi_tx_20/hdmi_tx_main.c
include/linux/amlogic/media/vout/hdmi_tx/hdmi_tx_ext.h
sound/soc/amlogic/meson/spdif_codec.c
sound/soc/amlogic/meson/tv.c
sound/soc/amlogic/meson/tv.h

index 24cb6e7..66e4d7f 100644 (file)
        spdif_codec: spdif_codec{
                #sound-dai-cells = <0>;
                compatible = "amlogic, aml-spdif-codec";
-               pinctrl-names = "audio_spdif";
-               pinctrl-0 = <&audio_spdif_pins>;
+               pinctrl-names = "audio_spdif_out",
+                                               "audio_spdif_out_mute",
+                                               "audio_spdif_in",
+                                               "audio_spdif_in_mute";
+               pinctrl-0 = <&audio_spdif_out_pins>;
+               pinctrl-1 = <&audio_spdif_out_mute_pins>;
+               pinctrl-2 = <&audio_spdif_in_pins>;
+               pinctrl-3 = <&audio_spdif_in_mute_pins>;
        };
 
        pcm_codec: pcm_codec{
                pinctrl-0 = <&aml_audio_i2s>;
                /*avout mute gpio*/
                mute_gpio-gpios = <&gpio GPIOZ_7 GPIO_ACTIVE_HIGH>;
+               /*switch ARC_IN & SPDIF_IN*/
+               source_switch-gpios = <&gpio GPIOZ_4 GPIO_ACTIVE_HIGH>;
                /*analog amp mute*/
                /*amp_mute_gpio-gpios = <&gpio GPIOZ_18 GPIO_ACTIVE_LOW>;*/
                aux_dev = <&tas5707>;
                };
                Channel_Mask {
                        /*i2s has 4 pins, 8channel, mux output*/
-                       Speaker_Channel_Mask = "i2s_0/1";
+                       Speaker0_Channel_Mask = "i2s_2/3";
                        DAC0_Channel_Mask = "i2s_2/3";
                        DAC1_Channel_Mask = "i2s_2/3";
                        EQ_DRC_Channel_Mask = "i2s_2/3";
                };
        };
        /*spdif*/
-       audio_spdif_pins: audio_spdif_pins {
-               in_mux {
+       audio_spdif_out_pins: audio_spdif_out_pins {
+               mux {
+                       groups = "spdif_out_z";
+                       function = "spdif_out";
+               };
+       };
+       audio_spdif_out_mute_pins: audio_spdif_out_mute_pins {
+               mux {
+                       groups = "GPIOZ_17";
+                       function = "gpio_periphs";
+               };
+       };
+       audio_spdif_in_pins: audio_spdif_in_pins {
+           mux {
                        groups = "spdif_in_z18";
                        function = "spdif_in";
                };
-               out_mux {
-                       groups = "spdif_out_z";
-                       function = "spdif_out";
+       };
+       audio_spdif_in_mute_pins: audio_spdif_in_mute_pins {
+           mux {
+                       groups = "GPIOZ_18";
+                       function = "gpio_periphs";
                };
        };
        /*pcm*/
index 0bb81ce..79a82b7 100644 (file)
        spdif_codec: spdif_codec{
                #sound-dai-cells = <0>;
                compatible = "amlogic, aml-spdif-codec";
-               pinctrl-names = "audio_spdif";
-               pinctrl-0 = <&audio_spdif_pins>;
+               pinctrl-names = "audio_spdif_out", "audio_spdif_out_mute";
+               pinctrl-0 = <&audio_spdif_out_pins>;
+               pinctrl-1 = <&audio_spdif_out_mute_pins>;
        };
 
        pcm_codec: pcm_codec{
                };
                Channel_Mask {
                        /*i2s has 4 pins, 8channel, mux output*/
-                       Speaker_Channel_Mask = "i2s_0/1";
+                       Speaker0_Channel_Mask = "i2s_2/3";
                        DAC0_Channel_Mask = "i2s_2/3";
                        DAC1_Channel_Mask = "i2s_2/3";
                        EQ_DRC_Channel_Mask = "i2s_2/3";
                };
        };
        /*spdif*/
-       audio_spdif_pins: audio_spdif_pins {
-               out_mux {
+       audio_spdif_out_pins: audio_spdif_out_pins {
+               mux {
                        groups = "spdif_out_dv";
                        function = "spdif_out";
                };
        };
+       audio_spdif_out_mute_pins: audio_spdif_out_mute_pins {
+               mux {
+                       groups = "GPIODV_6";
+                       function = "gpio_periphs";
+               };
+       };
        /*pcm*/
        aml_audio_pcm: aml_audio_pcm {
                mux {
index ba86c96..bc0e0ba 100644 (file)
        spdif_codec: spdif_codec{
                #sound-dai-cells = <0>;
                compatible = "amlogic, aml-spdif-codec";
-               pinctrl-names = "audio_spdif";
-               pinctrl-0 = <&audio_spdif_pins>;
+               pinctrl-names = "audio_spdif_out", "audio_spdif_out_mute";
+               pinctrl-0 = <&audio_spdif_out_pins>;
+               pinctrl-1 = <&audio_spdif_out_mute_pins>;
        };
 
        pcm_codec: pcm_codec{
                };
                Channel_Mask {
                        /*i2s has 4 pins, 8channel, mux output*/
-                       Speaker_Channel_Mask = "i2s_0/1";
+                       Speaker0_Channel_Mask = "i2s_2/3";
                        DAC0_Channel_Mask = "i2s_2/3";
                        DAC1_Channel_Mask = "i2s_2/3";
                        EQ_DRC_Channel_Mask = "i2s_2/3";
                };
        };
        /*spdif*/
-       audio_spdif_pins: audio_spdif_pins {
-               out_mux {
+       /*spdif*/
+       audio_spdif_out_pins: audio_spdif_out_pins {
+               mux {
                        groups = "spdif_out_dv";
                        function = "spdif_out";
                };
        };
+       audio_spdif_out_mute_pins: audio_spdif_out_mute_pins {
+               mux {
+                       groups = "GPIODV_6";
+                       function = "gpio_periphs";
+               };
+       };
        /*pcm*/
        aml_audio_pcm: aml_audio_pcm {
                mux {
index eb0bfb8..06dd29d 100644 (file)
        spdif_codec: spdif_codec{
                #sound-dai-cells = <0>;
                compatible = "amlogic, aml-spdif-codec";
-               pinctrl-names = "audio_spdif";
-               pinctrl-0 = <&audio_spdif_pins>;
+               pinctrl-names = "audio_spdif_out", "audio_spdif_out_mute";
+               pinctrl-0 = <&audio_spdif_out_pins>;
+               pinctrl-1 = <&audio_spdif_out_mute_pins>;
        };
 
        pcm_codec: pcm_codec{
                };
                Channel_Mask {
                        /*i2s has 4 pins, 8channel, mux output*/
-                       Speaker_Channel_Mask = "i2s_0/1";
+                       Speaker0_Channel_Mask = "i2s_2/3";
                        DAC0_Channel_Mask = "i2s_2/3";
                        DAC1_Channel_Mask = "i2s_2/3";
                        EQ_DRC_Channel_Mask = "i2s_2/3";
                };
        };
        /*spdif*/
-       audio_spdif_pins: audio_spdif_pins {
-               out_mux {
+       audio_spdif_out_pins: audio_spdif_out_pins {
+               mux {
                        groups = "spdif_out_dv";
                        function = "spdif_out";
                };
        };
+       audio_spdif_out_mute_pins: audio_spdif_out_mute_pins {
+               mux {
+                       groups = "GPIODV_6";
+                       function = "gpio_periphs";
+               };
+       };
        /*pcm*/
        aml_audio_pcm: aml_audio_pcm {
                mux {
index 0936c49..a6e7688 100644 (file)
@@ -1500,21 +1500,6 @@ static ssize_t store_config(struct device *dev,
                        hdmitx_device.flag_3dss = 0;
                        hdmi_set_3d(&hdmitx_device, T3D_DISABLE, 0);
                }
-       } else if (strncmp(buf, "audio_", 6) == 0) {
-               if (strncmp(buf+6, "off", 3) == 0) {
-                       hdmitx_audio_mute_op(0);
-                       pr_info(AUD "configure off\n");
-               } else if (strncmp(buf+6, "on", 2) == 0) {
-                       hdmitx_audio_mute_op(1);
-                       pr_info(AUD "configure on\n");
-               } else if (strncmp(buf+6, "auto", 4) == 0) {
-                       /* auto mode. if sink doesn't support current
-                        * audio format, then no audio output
-                        */
-                       hdmitx_device.tx_aud_cfg = 2;
-                       pr_info(AUD "configure auto\n");
-               } else
-                       pr_info(AUD "configure error\n");
        } else if (strncmp(buf, "sdr", 3) == 0) {
                data.features = 0x00010100;
                hdmitx_set_drm_pkt(&data);
@@ -1533,37 +1518,48 @@ static ssize_t store_config(struct device *dev,
        return count;
 }
 
-static ssize_t show_aud_mute(struct device *dev,
-       struct device_attribute *attr, char *buf)
+void hdmitx_ext_set_audio_output(int enable)
 {
-       int pos = 0;
+       hdmitx_audio_mute_op(enable);
+}
 
-       pos += snprintf(buf+pos, PAGE_SIZE, "%d\n",
-               atomic_read(&(hdmitx_device.kref_audio_mute)));
-       return pos;
+int hdmitx_ext_get_audio_status(void)
+{
+       return !!hdmitx_device.tx_aud_cfg;
 }
 
-static ssize_t store_aud_mute(struct device *dev,
-       struct device_attribute *attr, const char *buf, size_t count)
+void hdmitx_ext_set_i2s_mask(char ch_num, char ch_msk)
 {
-       atomic_t kref_audio_mute = hdmitx_device.kref_audio_mute;
+       struct hdmitx_dev *hdev = &hdmitx_device;
+       static unsigned int update_flag = -1;
 
-       if (buf[0] == '1') {
-               atomic_inc(&kref_audio_mute);
-               if (atomic_read(&kref_audio_mute) == 1)
-                       hdmitx_audio_mute_op(0);
-       }
-       if (buf[0] == '0') {
-               if (!(atomic_sub_and_test(0, &kref_audio_mute))) {
-                       atomic_dec(&kref_audio_mute);
-                       if (atomic_sub_and_test(0, &kref_audio_mute))
-                               hdmitx_audio_mute_op(1);
+       if (!((ch_num == 2) || (ch_num == 4) || (ch_num == 6)
+               || (ch_num == 8))) {
+               pr_info("err chn setting, must be 2, 4, 6 or 8, Rst as def\n");
+               hdev->aud_output_ch = 0;
+               if (update_flag != hdev->aud_output_ch) {
+                       update_flag = hdev->aud_output_ch;
+                       hdev->hdmi_ch = 0;
+                       hdmitx_set_audio(hdev, &(hdev->cur_audio_param));
                }
        }
+       if (ch_msk == 0) {
+               pr_info("err chn msk, must larger than 0\n");
+               return;
+       }
+       hdev->aud_output_ch = (ch_num << 4) + ch_msk;
+       if (update_flag != hdev->aud_output_ch) {
+               update_flag = hdev->aud_output_ch;
+               hdev->hdmi_ch = 0;
+               hdmitx_set_audio(hdev, &(hdev->cur_audio_param));
+       }
+}
 
-       hdmitx_device.kref_audio_mute = kref_audio_mute;
+char hdmitx_ext_get_i2s_mask(void)
+{
+       struct hdmitx_dev *hdev = &hdmitx_device;
 
-       return count;
+       return hdev->aud_output_ch & 0xf;
 }
 
 static ssize_t show_vid_mute(struct device *dev,
@@ -2107,70 +2103,6 @@ static ssize_t store_aud_ch(struct device *dev,
        return count;
 }
 
-/* hdmitx audio output channel */
-static ssize_t show_aud_output_chs(struct device *dev,
-       struct device_attribute *attr, char *buf)
-{
-       struct hdmitx_dev *hdev = &hdmitx_device;
-       int pos = 0;
-
-       if (hdev->aud_output_ch)
-               pos += snprintf(buf + pos, PAGE_SIZE,
-                       "Audio Output Channels: %x:%x\n",
-                       (hdev->aud_output_ch >> 4) & 0xf,
-                       (hdev->aud_output_ch & 0xf));
-
-       return pos;
-}
-
-/*
- * aud_output_chs CONFIGURE:
- *     [7:4] -- Output Channel Numbers, must be 2/4/6/8
- *     [3:0] -- Output Channel Mask, matched as CH3/2/1/0 R/L
- */
-static ssize_t store_aud_output_chs(struct device *dev,
-       struct device_attribute *attr, const char *buf, size_t count)
-{
-       struct hdmitx_dev *hdev = &hdmitx_device;
-       int tmp = -1;
-       int ret = 0;
-       unsigned long msk;
-       static unsigned int update_flag = -1;
-
-       if (isdigit(buf[0]))
-               tmp = buf[0] - '0';
-
-       if (!((tmp == 2) || (tmp == 4) || (tmp == 6) || (tmp == 8))) {
-               pr_info("err chn setting, must be 2, 4, 6 or 8, Rst as def\n");
-               hdev->aud_output_ch = 0;
-               if (update_flag != hdev->aud_output_ch) {
-                       update_flag = hdev->aud_output_ch;
-                       hdev->hdmi_ch = 0;
-                       hdmitx_set_audio(hdev, &(hdev->cur_audio_param));
-               }
-               return count;
-       }
-
-       /* get channel no. For I2S, there are 4 I2S_in[3:0] */
-       if ((buf[1] == ':') && (isxdigit(buf[2])))
-               ret = kstrtoul(&buf[2], 16, &msk);
-       else
-               msk = 0;
-       if (ret || (msk == 0)) {
-               pr_info("err chn msk, must larger than 0\n");
-               return count;
-       }
-
-       hdev->aud_output_ch = (tmp << 4) + msk;
-
-       if (update_flag != hdev->aud_output_ch) {
-               update_flag = hdev->aud_output_ch;
-               hdev->hdmi_ch = 0;
-               hdmitx_set_audio(hdev, &(hdev->cur_audio_param));
-       }
-       return count;
-}
-
 /*
  *  1: set avmute
  * -1: clear avmute
@@ -2675,7 +2607,6 @@ static ssize_t show_support_3d(struct device *dev,
 static DEVICE_ATTR(disp_mode, 0664, show_disp_mode, store_disp_mode);
 static DEVICE_ATTR(attr, 0664, show_attr, store_attr);
 static DEVICE_ATTR(aud_mode, 0644, show_aud_mode, store_aud_mode);
-static DEVICE_ATTR(aud_mute, 0644, show_aud_mute, store_aud_mute);
 static DEVICE_ATTR(vid_mute, 0644, show_vid_mute, store_vid_mute);
 static DEVICE_ATTR(edid, 0644, show_edid, store_edid);
 static DEVICE_ATTR(rawedid, 0444, show_rawedid, NULL);
@@ -2691,8 +2622,6 @@ static DEVICE_ATTR(dv_cap, 0444, show_dv_cap, NULL);
 static DEVICE_ATTR(dc_cap, 0444, show_dc_cap, NULL);
 static DEVICE_ATTR(valid_mode, 0664, show_valid_mode, store_valid_mode);
 static DEVICE_ATTR(aud_ch, 0664, show_aud_ch, store_aud_ch);
-static DEVICE_ATTR(aud_output_chs, 0664, show_aud_output_chs,
-       store_aud_output_chs);
 static DEVICE_ATTR(avmute, 0664, show_avmute, store_avmute);
 static DEVICE_ATTR(vic, 0664, show_vic, store_vic);
 static DEVICE_ATTR(phy, 0664, show_phy, store_phy);
@@ -3737,7 +3666,6 @@ static int amhdmitx_probe(struct platform_device *pdev)
        ret = device_create_file(dev, &dev_attr_disp_mode);
        ret = device_create_file(dev, &dev_attr_attr);
        ret = device_create_file(dev, &dev_attr_aud_mode);
-       ret = device_create_file(dev, &dev_attr_aud_mute);
        ret = device_create_file(dev, &dev_attr_vid_mute);
        ret = device_create_file(dev, &dev_attr_edid);
        ret = device_create_file(dev, &dev_attr_rawedid);
@@ -3752,7 +3680,6 @@ static int amhdmitx_probe(struct platform_device *pdev)
        ret = device_create_file(dev, &dev_attr_hdr_cap);
        ret = device_create_file(dev, &dev_attr_dv_cap);
        ret = device_create_file(dev, &dev_attr_aud_ch);
-       ret = device_create_file(dev, &dev_attr_aud_output_chs);
        ret = device_create_file(dev, &dev_attr_avmute);
        ret = device_create_file(dev, &dev_attr_vic);
        ret = device_create_file(dev, &dev_attr_phy);
@@ -3832,7 +3759,6 @@ static int amhdmitx_remove(struct platform_device *pdev)
        device_remove_file(dev, &dev_attr_disp_mode);
        device_remove_file(dev, &dev_attr_attr);
        device_remove_file(dev, &dev_attr_aud_mode);
-       device_remove_file(dev, &dev_attr_aud_mute);
        device_remove_file(dev, &dev_attr_vid_mute);
        device_remove_file(dev, &dev_attr_edid);
        device_remove_file(dev, &dev_attr_rawedid);
@@ -3857,7 +3783,6 @@ static int amhdmitx_remove(struct platform_device *pdev)
        device_remove_file(dev, &dev_attr_sspll);
        device_remove_file(dev, &dev_attr_rxsense_policy);
        device_remove_file(dev, &dev_attr_hdcp_pwr);
-       device_remove_file(dev, &dev_attr_aud_output_chs);
        device_remove_file(dev, &dev_attr_div40);
        device_remove_file(dev, &dev_attr_hdcp_repeater);
        device_remove_file(dev, &dev_attr_hdcp22_type);
index 3657e84..f5907bd 100644 (file)
 void direct_hdcptx14_start(void);
 void direct_hdcptx14_stop(void);
 
+/*
+ * HDMI TX output enable, such as ACRPacket/AudInfo/AudSample
+ * enable: 1, normal output;  0: disable output
+ */
+void hdmitx_ext_set_audio_output(int enable);
+
+/*
+ * return Audio output status
+ * 1: normal output status;  0: output disabled
+ */
+int hdmitx_ext_get_audio_status(void);
+
+/*
+ * For I2S interface, there are four input ports
+ * I2S_0/I2S_1/I2S_2/I2S_3
+ * ch_num: must be 2/4/6/8
+ * ch_msk: Mask for channel_num
+ * 2ch via I2S_0, set ch_num = 2 and ch_msk = 1
+ * 4ch via I2S_1/I2S_2, set set ch_num = 4 and ch_msk = 6
+ */
+void hdmitx_ext_set_i2s_mask(char ch_num, char ch_msk);
+
+/*
+ * get I2S mask
+ */
+char hdmitx_ext_get_i2s_mask(void);
+
 #endif
index 6157f0d..a9b66cf 100644 (file)
@@ -25,6 +25,9 @@
 #include <sound/initval.h>
 #include <linux/of.h>
 #include <linux/pinctrl/consumer.h>
+#ifdef CONFIG_AMLOGIC_HDMITX
+#include <linux/amlogic/media/vout/hdmi_tx/hdmi_tx_ext.h>
+#endif
 
 #define DRV_NAME "spdif-dit"
 
 
 static struct spdif_codec {
        struct device *pdev;
-       struct pinctrl *p_pinctrl;
-       unsigned int spdif_pinmux;
-       bool aml_audio_spdif_mute_flag;
+       struct pinctrl *p_pinctrl_out;
+       struct pinctrl_state *p_pinctrl_out_state;
+       struct pinctrl *p_pinctrl_out_mute;
+       struct pinctrl_state *p_pinctrl_out_mute_state;
+       bool spdif_pinmux_out;
+       struct pinctrl *p_pinctrl_in;
+       struct pinctrl_state *p_pinctrl_in_state;
+       struct pinctrl *p_pinctrl_in_mute;
+       struct pinctrl_state *p_pinctrl_in_mute_state;
+       bool spdif_pinmux_in;
+#ifdef CONFIG_AMLOGIC_HDMITX
+       bool aml_audio_hdmiout_mute_flag;
+#endif
 } v_spdif_codec;
 
 static struct snd_soc_dai_driver dit_stub_dai = {
@@ -59,54 +72,197 @@ static struct snd_soc_dai_driver dit_stub_dai = {
 
 void aml_spdif_pinmux_init(struct device *dev)
 {
-       if (!v_spdif_codec.spdif_pinmux) {
-               v_spdif_codec.spdif_pinmux = 1;
-               v_spdif_codec.p_pinctrl =
-                       devm_pinctrl_get_select(dev, "audio_spdif");
-               if (IS_ERR(v_spdif_codec.p_pinctrl)) {
-                       v_spdif_codec.p_pinctrl = NULL;
-                       dev_err(dev, "aml_spdif_pinmux_init can't get pinctrl\n");
+       v_spdif_codec.p_pinctrl_out_mute =
+               devm_pinctrl_get_select(dev, "audio_spdif_out_mute");
+       if (IS_ERR(v_spdif_codec.p_pinctrl_out_mute)) {
+               v_spdif_codec.p_pinctrl_out_mute = NULL;
+               dev_err(dev, "audio_spdif_out_mute can't get pinctrl\n");
+       } else {
+               v_spdif_codec.p_pinctrl_out_mute_state =
+                       pinctrl_lookup_state(v_spdif_codec.p_pinctrl_out_mute,
+                               "audio_spdif_out_mute");
+               if (IS_ERR(v_spdif_codec.p_pinctrl_out_mute_state)) {
+                       devm_pinctrl_put(v_spdif_codec.p_pinctrl_out_mute);
+                       dev_err(dev, "audio_spdif_out_mute can't get pinctrl\n");
                }
        }
+
+       v_spdif_codec.p_pinctrl_out =
+               devm_pinctrl_get_select(dev, "audio_spdif_out");
+       if (IS_ERR(v_spdif_codec.p_pinctrl_out)) {
+               v_spdif_codec.p_pinctrl_out = NULL;
+               dev_err(dev, "audio_spdif_out can't get pinctrl\n");
+       } else {
+               v_spdif_codec.p_pinctrl_out_state =
+                       pinctrl_lookup_state(v_spdif_codec.p_pinctrl_out,
+                               "audio_spdif_out");
+               if (IS_ERR(v_spdif_codec.p_pinctrl_out_state)) {
+                       devm_pinctrl_put(v_spdif_codec.p_pinctrl_out);
+                       dev_err(dev, "audio_spdif_out can't get pinctrl\n");
+               }
+       }
+
+       v_spdif_codec.p_pinctrl_in_mute =
+               devm_pinctrl_get_select(dev, "audio_spdif_in_mute");
+       if (IS_ERR(v_spdif_codec.p_pinctrl_in_mute)) {
+               v_spdif_codec.p_pinctrl_in_mute = NULL;
+               dev_err(dev, "audio_spdif_in_mute can't get pinctrl\n");
+       }
+       v_spdif_codec.p_pinctrl_in =
+               devm_pinctrl_get_select(dev, "audio_spdif_in");
+       if (IS_ERR(v_spdif_codec.p_pinctrl_in)) {
+               v_spdif_codec.p_pinctrl_in = NULL;
+               dev_err(dev, "audio_spdif_in can't get pinctrl\n");
+       }
 }
 
 void aml_spdif_pinmux_deinit(struct device *dev)
 {
-       dev_dbg(dev, "aml_spdif_mute\n");
-       if (v_spdif_codec.spdif_pinmux) {
-               v_spdif_codec.spdif_pinmux = 0;
-               if (v_spdif_codec.p_pinctrl)
-                       devm_pinctrl_put(v_spdif_codec.p_pinctrl);
-       }
+       if (v_spdif_codec.p_pinctrl_out)
+               devm_pinctrl_put(v_spdif_codec.p_pinctrl_out);
+
+       if (v_spdif_codec.p_pinctrl_out_mute)
+               devm_pinctrl_put(v_spdif_codec.p_pinctrl_out_mute);
+
+       if (v_spdif_codec.p_pinctrl_in)
+               devm_pinctrl_put(v_spdif_codec.p_pinctrl_in);
+
+       if (v_spdif_codec.p_pinctrl_in_mute)
+               devm_pinctrl_put(v_spdif_codec.p_pinctrl_in_mute);
 }
+
 static int aml_audio_set_spdif_mute(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
+                                       struct snd_ctl_elem_value *ucontrol)
 {
-       v_spdif_codec.aml_audio_spdif_mute_flag =
-               ucontrol->value.integer.value[0];
+       v_spdif_codec.spdif_pinmux_out =
+                       ucontrol->value.integer.value[0];
 
        pr_info("aml_audio_set_spdif_mute: flag=%d\n",
-               v_spdif_codec.aml_audio_spdif_mute_flag);
+                               v_spdif_codec.spdif_pinmux_out);
 
-       if (v_spdif_codec.aml_audio_spdif_mute_flag)
-               aml_spdif_pinmux_deinit(v_spdif_codec.pdev);
-       else
-               aml_spdif_pinmux_init(v_spdif_codec.pdev);
+       if (v_spdif_codec.spdif_pinmux_out == 0 &&
+                       v_spdif_codec.p_pinctrl_out &&
+                       v_spdif_codec.p_pinctrl_out_state)
+               pinctrl_select_state(v_spdif_codec.p_pinctrl_out,
+                       v_spdif_codec.p_pinctrl_out_state);
+       else if (v_spdif_codec.spdif_pinmux_out == 1 &&
+                       v_spdif_codec.p_pinctrl_out_mute &&
+                       v_spdif_codec.p_pinctrl_out_mute_state)
+               pinctrl_select_state(v_spdif_codec.p_pinctrl_out_mute,
+                       v_spdif_codec.p_pinctrl_out_mute_state);
        return 0;
 }
 
 static int aml_audio_get_spdif_mute(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
+                                       struct snd_ctl_elem_value *ucontrol)
 {
        ucontrol->value.integer.value[0] =
-               v_spdif_codec.aml_audio_spdif_mute_flag;
+                       v_spdif_codec.spdif_pinmux_out;
        return 0;
 }
 
+#ifdef CONFIG_AMLOGIC_HDMITX
+/* call HDMITX API to enable/disable internal audio out */
+static 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();
+
+       v_spdif_codec.aml_audio_hdmiout_mute_flag =
+                       ucontrol->value.integer.value[0];
+       return 0;
+}
+
+static int aml_set_hdmi_out_audio(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       bool mute = ucontrol->value.integer.value[0];
+
+       if (v_spdif_codec.aml_audio_hdmiout_mute_flag != mute) {
+               hdmitx_ext_set_audio_output(!mute);
+               v_spdif_codec.aml_audio_hdmiout_mute_flag = mute;
+       }
+       return 0;
+}
+
+static const char * const hdmi_out_channel_mask_texts[] = {
+               "SPDIF",
+               "2CH_I2S_0/1",
+               "2CH_I2S_2/3",
+               "2CH_I2S_4/5",
+               "2CH_I2S_6/7",
+               "4CH_I2S",
+               "6CH_I2S",
+               "8CH_I2S",
+};
+
+static const struct soc_enum hdmi_out_channel_mask_texts_enum =
+       SOC_ENUM_SINGLE(SND_SOC_NOPM, 0,
+               ARRAY_SIZE(hdmi_out_channel_mask_texts),
+               hdmi_out_channel_mask_texts);
+
+static int aml_get_hdmi_out_channel_mask(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       char channel_mask = hdmitx_ext_get_i2s_mask();
+       int index = 0;
+
+       if (channel_mask == 0x1)
+               index = 1;
+       else if (channel_mask == 0x2)
+               index = 2;
+       else if (channel_mask == 0x4)
+               index = 3;
+       else if (channel_mask == 0x8)
+               index = 4;
+       else if (channel_mask == 0x3)
+               index = 5;
+       else if (channel_mask == 0x7)
+               index = 6;
+       else if (channel_mask == 0xf)
+               index = 7;
+       else
+               index = 0;
+       ucontrol->value.integer.value[0] = index;
+       return 0;
+}
+
+static int aml_set_hdmi_out_channel_mask(struct snd_kcontrol *kcontrol,
+                         struct snd_ctl_elem_value *ucontrol)
+{
+       int index = ucontrol->value.integer.value[0];
+
+       if (index == 1)
+               hdmitx_ext_set_i2s_mask(2, 0x1);
+       else if (index == 2)
+               hdmitx_ext_set_i2s_mask(2, 0x2);
+       else if (index == 3)
+               hdmitx_ext_set_i2s_mask(2, 0x4);
+       else if (index == 4)
+               hdmitx_ext_set_i2s_mask(2, 0x8);
+       else if (index == 5)
+               hdmitx_ext_set_i2s_mask(4, 0x3);
+       else if (index == 6)
+               hdmitx_ext_set_i2s_mask(6, 0x7);
+       else if (index == 7)
+               hdmitx_ext_set_i2s_mask(8, 0xf);
+       return 0;
+}
+#endif
+
 static const struct snd_kcontrol_new spdif_controls[] = {
        SOC_SINGLE_BOOL_EXT("Audio spdif mute",
                            0, aml_audio_get_spdif_mute,
                            aml_audio_set_spdif_mute),
+#ifdef CONFIG_AMLOGIC_HDMITX
+       SOC_SINGLE_BOOL_EXT("Audio hdmi-out mute",
+                               0, aml_get_hdmi_out_audio,
+                               aml_set_hdmi_out_audio),
+       SOC_ENUM_EXT("Audio hdmi-out channel mask",
+                               hdmi_out_channel_mask_texts_enum,
+                               aml_get_hdmi_out_channel_mask,
+                               aml_set_hdmi_out_channel_mask),
+#endif
 };
 
 static int spdif_probe(struct snd_soc_codec *codec)
@@ -118,42 +274,11 @@ static struct snd_soc_codec_driver soc_codec_spdif_dit = {
        .probe =        spdif_probe,
 };
 
-static ssize_t spdif_mute_show(struct device *dev,
-                              struct device_attribute *attr, char *buf)
-{
-       if (v_spdif_codec.spdif_pinmux)
-               return sprintf(buf, "spdif_unmute\n");
-       else
-               return sprintf(buf, "spdif_mute\n");
-
-}
-
-static ssize_t spdif_mute_set(struct device *dev,
-                             struct device_attribute *attr,
-                             const char *buf, size_t count)
-{
-       if (strncmp(buf, "spdif_mute", 10))
-               aml_spdif_pinmux_init(dev);
-       else if (strncmp(buf, "spdif_unmute", 12))
-               aml_spdif_pinmux_deinit(dev);
-       else
-               dev_err(dev, "spdif set the wrong value\n");
-
-       return count;
-}
-
-static DEVICE_ATTR(spdif_mute, 0660, spdif_mute_show, spdif_mute_set);
-
 static int spdif_dit_probe(struct platform_device *pdev)
 {
-       int ret = device_create_file(&pdev->dev, &dev_attr_spdif_mute);
-
        v_spdif_codec.pdev = &pdev->dev;
 
        aml_spdif_pinmux_init(&pdev->dev);
-       if (ret < 0)
-               dev_err(&pdev->dev,
-                       "spdif: failed to add spdif_mute sysfs: %d\n", ret);
 
        return snd_soc_register_codec(&pdev->dev, &soc_codec_spdif_dit,
                                      &dit_stub_dai, 1);
@@ -162,7 +287,6 @@ static int spdif_dit_probe(struct platform_device *pdev)
 static int spdif_dit_remove(struct platform_device *pdev)
 {
        aml_spdif_pinmux_deinit(&pdev->dev);
-       device_remove_file(&pdev->dev, &dev_attr_spdif_mute);
        snd_soc_unregister_codec(&pdev->dev);
 
        return 0;
@@ -200,7 +324,6 @@ static void __exit spdif_codec_exit(void)
 module_init(spdif_codec_init);
 module_exit(spdif_codec_exit);
 
-MODULE_AUTHOR("Steve Chen <schen@mvista.com>");
 MODULE_DESCRIPTION("SPDIF dummy codec driver");
 MODULE_LICENSE("GPL");
 MODULE_ALIAS("platform:" DRV_NAME);
index 03737a9..460d735 100644 (file)
 
 #define DRV_NAME "aml_snd_card_tv"
 
-static int aml_audio_Hardware_resample;
-static int Speaker_Channel_Mask = 1;
-static int EQ_DRC_Channel_Mask;
-static int DAC0_Channel_Mask;
-static int DAC1_Channel_Mask;
-static int Spdif_samesource_Channel_Mask;
-
 static unsigned int aml_EQ_param_length = 100;
 static unsigned int aml_EQ_param[100] = {
        /*channel 1 param*/
@@ -319,7 +312,11 @@ static int aml_hardware_resample_get_enum(
        struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
-       ucontrol->value.enumerated.item[0] = aml_audio_Hardware_resample;
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+       struct aml_audio_private_data *p_aml_audio =
+                       snd_soc_card_get_drvdata(card);
+       ucontrol->value.enumerated.item[0] =
+                       p_aml_audio->aml_audio_Hardware_resample;
        return 0;
 }
 
@@ -352,7 +349,7 @@ static int aml_hardware_resample_set_enum(
        else
                return 0;
 
-       aml_audio_Hardware_resample = index;
+       p_aml_audio->aml_audio_Hardware_resample = index;
 
        if (index > 0
                && p_aml_audio
@@ -367,10 +364,7 @@ static const struct snd_soc_dapm_widget aml_asoc_dapm_widgets[] = {
        SND_SOC_DAPM_OUTPUT("LINEOUT"),
 };
 
-int audio_in_GPIO;
-struct gpio_desc *av_source;
-static const char * const audio_in_switch_texts[] = { "AV", "Karaok"};
-
+static const char * const audio_in_switch_texts[] = { "SPDIF_IN", "ARC_IN"};
 static const struct soc_enum audio_in_switch_enum = SOC_ENUM_SINGLE(
                SND_SOC_NOPM, 0, ARRAY_SIZE(audio_in_switch_texts),
                audio_in_switch_texts);
@@ -378,28 +372,40 @@ static const struct soc_enum audio_in_switch_enum = SOC_ENUM_SINGLE(
 static int aml_get_audio_in_switch(struct snd_kcontrol *kcontrol,
                struct snd_ctl_elem_value *ucontrol) {
 
-       if (audio_in_GPIO == 0) {
-               ucontrol->value.enumerated.item[0] = 0;
-               pr_info("audio in source: AV\n");
-       } else if (audio_in_GPIO == 1) {
-               ucontrol->value.enumerated.item[0] = 1;
-               pr_info("audio in source: Karaok\n");
-       }
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+       struct aml_audio_private_data *p_aml_audio;
+
+       p_aml_audio = snd_soc_card_get_drvdata(card);
+       ucontrol->value.integer.value[0] = p_aml_audio->audio_in_GPIO;
        return 0;
 }
 
 static int aml_set_audio_in_switch(struct snd_kcontrol *kcontrol,
                struct snd_ctl_elem_value *ucontrol) {
+
+       struct snd_soc_card *card = snd_kcontrol_chip(kcontrol);
+       struct aml_audio_private_data *p_aml_audio;
+
+       p_aml_audio = snd_soc_card_get_drvdata(card);
+
        if (ucontrol->value.enumerated.item[0] == 0) {
-               gpiod_direction_output(av_source,
+               if (p_aml_audio->audio_in_GPIO_inv == 0) {
+                       gpiod_direction_output(p_aml_audio->source_switch,
+                                          GPIOF_OUT_INIT_HIGH);
+               } else {
+                       gpiod_direction_output(p_aml_audio->source_switch,
                                           GPIOF_OUT_INIT_LOW);
-               audio_in_GPIO = 0;
-               pr_info("Set audio in source: AV\n");
+               }
+               p_aml_audio->audio_in_GPIO = 0;
        } else if (ucontrol->value.enumerated.item[0] == 1) {
-               gpiod_direction_output(av_source,
+               if (p_aml_audio->audio_in_GPIO_inv == 0) {
+                       gpiod_direction_output(p_aml_audio->source_switch,
+                                          GPIOF_OUT_INIT_LOW);
+               } else {
+                       gpiod_direction_output(p_aml_audio->source_switch,
                                           GPIOF_OUT_INIT_HIGH);
-               audio_in_GPIO = 1;
-               pr_info("Set audio in source: Karaok\n");
+               }
+               p_aml_audio->audio_in_GPIO = 1;
        }
        return 0;
 }
@@ -1304,11 +1310,19 @@ static int aml_asoc_init(struct snd_soc_pcm_runtime *rtd)
                                        hp_controls, ARRAY_SIZE(hp_controls));
        }
 
-       /*It is used for KaraOK, */
-       av_source = gpiod_get(card->dev, "av_source", GPIOD_OUT_LOW);
-       if (!IS_ERR(av_source)) {
-               pr_info("%s, make av_source gpio low!\n", __func__);
-               gpiod_direction_output(av_source, GPIOF_OUT_INIT_LOW);
+       /*It is used for switch of ARC_IN & SPDIF_IN */
+       p_aml_audio->source_switch = gpiod_get(card->dev,
+                               "source_switch", GPIOF_OUT_INIT_HIGH);
+       if (!IS_ERR(p_aml_audio->source_switch)) {
+               of_property_read_u32(card->dev->of_node, "source_switch_inv",
+                               &p_aml_audio->audio_in_GPIO_inv);
+               if (p_aml_audio->audio_in_GPIO_inv == 0) {
+                       gpiod_direction_output(p_aml_audio->source_switch,
+                               GPIOF_OUT_INIT_HIGH);
+               } else {
+                       gpiod_direction_output(p_aml_audio->source_switch,
+                               GPIOF_OUT_INIT_LOW);
+               }
                snd_soc_add_card_controls(card, av_controls,
                                        ARRAY_SIZE(av_controls));
        }
@@ -1362,10 +1376,13 @@ static int check_channel_mask(const char *str)
 
 static void parse_speaker_channel_mask(struct snd_soc_card *card)
 {
+       struct aml_audio_private_data *p_aml_audio;
        struct device_node *np;
        const char *str;
        int ret;
 
+       p_aml_audio = snd_soc_card_get_drvdata(card);
+
        /* channel mask */
        np = of_get_child_by_name(card->dev->of_node,
                        "Channel_Mask");
@@ -1376,29 +1393,49 @@ static void parse_speaker_channel_mask(struct snd_soc_card *card)
                return;
        }
 
-       /* Speaker need Audio Effcet from user space by i2s2/3,
-        * mux i2s2/3 to layout pin
-        */
-       of_property_read_string(np, "Speaker_Channel_Mask", &str);
+       /* ext Speaker mask*/
+       of_property_read_string(np, "Speaker0_Channel_Mask", &str);
        ret = check_channel_mask(str);
        if (ret >= 0) {
-               Speaker_Channel_Mask = ret;
+               p_aml_audio->Speaker0_Channel_Mask = ret;
                aml_aiu_update_bits(AIU_I2S_OUT_CFG,
-                               0x3 << (Speaker_Channel_Mask * 2),
-                               1 << (Speaker_Channel_Mask * 2));
-               if (Speaker_Channel_Mask == 0) {
-                       aml_aiu_update_bits(AIU_I2S_OUT_CFG,
-                               0x3 << 2, 0 << 2);
-               }
+                               0x3, p_aml_audio->Speaker0_Channel_Mask);
+       }
+       of_property_read_string(np, "Speaker1_Channel_Mask", &str);
+       ret = check_channel_mask(str);
+       if (ret >= 0) {
+               p_aml_audio->Speaker1_Channel_Mask = ret;
+               aml_aiu_update_bits(AIU_I2S_OUT_CFG,
+                               0x3 << 2,
+                               p_aml_audio->Speaker1_Channel_Mask << 2);
+       }
+       of_property_read_string(np, "Speaker2_Channel_Mask", &str);
+       ret = check_channel_mask(str);
+       if (ret >= 0) {
+               p_aml_audio->Speaker2_Channel_Mask = ret;
+               aml_aiu_update_bits(AIU_I2S_OUT_CFG,
+                               0x3 << 4,
+                               p_aml_audio->Speaker2_Channel_Mask << 4);
+       }
+       of_property_read_string(np, "Speaker3_Channel_Mask", &str);
+       ret = check_channel_mask(str);
+       if (ret >= 0) {
+               p_aml_audio->Speaker3_Channel_Mask = ret;
+               aml_aiu_update_bits(AIU_I2S_OUT_CFG,
+                               0x3 << 6,
+                               p_aml_audio->Speaker3_Channel_Mask << 6);
        }
 }
 
 static void parse_dac_channel_mask(struct snd_soc_card *card)
 {
+       struct aml_audio_private_data *p_aml_audio;
        struct device_node *np;
        const char *str;
        int ret;
 
+       p_aml_audio = snd_soc_card_get_drvdata(card);
+
        /* channel mask */
        np = of_get_child_by_name(card->dev->of_node,
                        "Channel_Mask");
@@ -1413,26 +1450,29 @@ static void parse_dac_channel_mask(struct snd_soc_card *card)
        of_property_read_string(np, "DAC0_Channel_Mask", &str);
        ret = check_channel_mask(str);
        if (ret >= 0) {
-               DAC0_Channel_Mask = ret;
+               p_aml_audio->DAC0_Channel_Mask = ret;
                aml_aiu_update_bits(AIU_ACODEC_CTRL, 0x3,
-                               DAC0_Channel_Mask);
+                               p_aml_audio->DAC0_Channel_Mask);
        }
        /*Acodec DAC1 selects i2s source*/
        of_property_read_string(np, "DAC1_Channel_Mask", &str);
        ret = check_channel_mask(str);
        if (ret >= 0) {
-               DAC1_Channel_Mask = ret;
+               p_aml_audio->DAC1_Channel_Mask = ret;
                aml_aiu_update_bits(AIU_ACODEC_CTRL, 0x3 << 8,
-                               DAC1_Channel_Mask << 8);
+                               p_aml_audio->DAC1_Channel_Mask << 8);
        }
 }
 
 static void parse_eqdrc_channel_mask(struct snd_soc_card *card)
 {
+       struct aml_audio_private_data *p_aml_audio;
        struct device_node *np;
        const char *str;
        int ret;
 
+       p_aml_audio = snd_soc_card_get_drvdata(card);
+
        /* channel mask */
        np = of_get_child_by_name(card->dev->of_node,
                        "Channel_Mask");
@@ -1447,10 +1487,10 @@ static void parse_eqdrc_channel_mask(struct snd_soc_card *card)
        of_property_read_string(np, "EQ_DRC_Channel_Mask", &str);
        ret = check_channel_mask(str);
        if (ret >= 0) {
-               EQ_DRC_Channel_Mask = ret;
+               p_aml_audio->EQ_DRC_Channel_Mask = ret;
                 /*i2s in sel*/
                aml_eqdrc_update_bits(AED_TOP_CTL, (0x7 << 1),
-                       (EQ_DRC_Channel_Mask << 1));
+                       (p_aml_audio->EQ_DRC_Channel_Mask << 1));
                aml_eqdrc_write(AED_ED_CTL, 1);
                /* disable noise gate*/
                aml_eqdrc_write(AED_NG_CTL, (3 << 30));
@@ -1464,9 +1504,9 @@ static void parse_eqdrc_channel_mask(struct snd_soc_card *card)
                        "Spdif_samesource_Channel_Mask", &str);
        ret = check_channel_mask(str);
        if (ret >= 0) {
-               Spdif_samesource_Channel_Mask = ret;
+               p_aml_audio->Spdif_samesource_Channel_Mask = ret;
                aml_aiu_update_bits(AIU_I2S_MISC, 0x7 << 5,
-                               Spdif_samesource_Channel_Mask << 5);
+                       p_aml_audio->Spdif_samesource_Channel_Mask << 5);
        }
 
 }
@@ -1474,10 +1514,13 @@ static void parse_eqdrc_channel_mask(struct snd_soc_card *card)
 /* spdif same source with i2s */
 static void parse_samesource_channel_mask(struct snd_soc_card *card)
 {
+       struct aml_audio_private_data *p_aml_audio;
        struct device_node *np;
        const char *str;
        int ret;
 
+       p_aml_audio = snd_soc_card_get_drvdata(card);
+
        /* channel mask */
        np = of_get_child_by_name(card->dev->of_node,
                        "Channel_Mask");
@@ -1495,9 +1538,9 @@ static void parse_samesource_channel_mask(struct snd_soc_card *card)
                        "Spdif_samesource_Channel_Mask", &str);
        ret = check_channel_mask(str);
        if (ret >= 0) {
-               Spdif_samesource_Channel_Mask = ret;
+               p_aml_audio->Spdif_samesource_Channel_Mask = ret;
                aml_aiu_update_bits(AIU_I2S_MISC, 0x7 << 5,
-                               Spdif_samesource_Channel_Mask << 5);
+                       p_aml_audio->Spdif_samesource_Channel_Mask << 5);
        }
 
 }
index ab04e42..6d7a2cc 100644 (file)
@@ -74,6 +74,18 @@ struct aml_audio_private_data {
 #ifdef CONFIG_AMLOGIC_MEDIA_TVIN_HDMI
        int atmos_edid_enable;
 #endif
+       int aml_audio_Hardware_resample;
+       int Speaker0_Channel_Mask;
+       int Speaker1_Channel_Mask;
+       int Speaker2_Channel_Mask;
+       int Speaker3_Channel_Mask;
+       int EQ_DRC_Channel_Mask;
+       int DAC0_Channel_Mask;
+       int DAC1_Channel_Mask;
+       int Spdif_samesource_Channel_Mask;
+       int audio_in_GPIO;
+       int audio_in_GPIO_inv;
+       struct gpio_desc *source_switch;
 };
 
 struct codec_info {