tegra: hdmi: add hdmi_audio capability exposure via sysfs
Emma Yan [Wed, 10 Apr 2013 08:10:27 +0000 (16:10 +0800)]
Add checking of the CEA extension bit 6 of byte #3 and expose this
information for userspace to set audio path properly.

Bug 1261178

Change-Id: Id2780f735da13c7292f269d7ddd9a87b3d09d0d6
Signed-off-by: Emma Yan <eyan@nvidia.com>
Reviewed-on: http://git-master/r/218151
Reviewed-by: Riham Haidar <rhaidar@nvidia.com>
Tested-by: Riham Haidar <rhaidar@nvidia.com>

drivers/video/tegra/dc/edid.c
drivers/video/tegra/dc/edid.h
drivers/video/tegra/dc/hdmi.c

index 57cbd61..3f3368c 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2010 Google, Inc.
  * Author: Erik Gilling <konkers@android.com>
  *
- * Copyright (c) 2010-2012, NVIDIA CORPORATION, All rights reserved.
+ * Copyright (c) 2010-2013, NVIDIA CORPORATION, All rights reserved.
  *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
@@ -32,6 +32,7 @@ struct tegra_edid_pvt {
        struct tegra_edid_hdmi_eld      eld;
        bool                            support_stereo;
        bool                            support_underscan;
+       bool                            support_audio;
        /* Note: dc_edid must remain the last member */
        struct tegra_dc_edid            dc_edid;
 };
@@ -196,6 +197,7 @@ int tegra_edid_parse_ext_block(const u8 *raw, int idx,
        int i;
        bool basic_audio = false;
 
+       edid->support_audio = 0;
        ptr = &raw[0];
 
        /* If CEA 861 block get info for eld struct */
@@ -210,6 +212,7 @@ int tegra_edid_parse_ext_block(const u8 *raw, int idx,
                         * If there is a Speaker Alloc block this will
                         * get over written with that value */
                        basic_audio = true;
+                       edid->support_audio = 1;
                }
        }
 
@@ -497,6 +500,14 @@ fail:
        return ret;
 }
 
+int tegra_edid_audio_supported(struct tegra_edid *edid)
+{
+       if ((!edid) || (!edid->data))
+               return 0;
+
+       return edid->data->support_audio;
+}
+
 int tegra_edid_underscan_supported(struct tegra_edid *edid)
 {
        if ((!edid) || (!edid->data))
index 77db36f..2e24645 100644 (file)
@@ -4,6 +4,8 @@
  * Copyright (C) 2010 Google, Inc.
  * Author: Erik Gilling <konkers@android.com>
  *
+ * Copyright (c) 2010-2013, NVIDIA CORPORATION, All rights reserved.
+ *
  * This software is licensed under the terms of the GNU General Public
  * License version 2, as published by the Free Software Foundation, and
  * may be copied, distributed, and modified under those terms.
@@ -59,4 +61,5 @@ struct tegra_dc_edid *tegra_edid_get_data(struct tegra_edid *edid);
 void tegra_edid_put_data(struct tegra_dc_edid *data);
 
 int tegra_edid_underscan_supported(struct tegra_edid *edid);
+int tegra_edid_audio_supported(struct tegra_edid *edid);
 #endif
index d3f7d7f..1cc6c01 100644 (file)
@@ -92,6 +92,7 @@ struct tegra_dc_hdmi_data {
 
 #ifdef CONFIG_SWITCH
        struct switch_dev               hpd_switch;
+       struct switch_dev               audio_switch;
 #endif
        struct tegra_hdmi_out           info;
 
@@ -831,6 +832,8 @@ void tegra_dc_hdmi_detect_config(struct tegra_dc *dc,
 #ifdef CONFIG_SWITCH
        hdmi->hpd_switch.state = 0;
        switch_set_state(&hdmi->hpd_switch, 1);
+       hdmi->audio_switch.state = 0;
+       switch_set_state(&hdmi->audio_switch, tegra_edid_audio_supported(hdmi->edid) ? 1 : 0);
 #endif
        dev_info(&dc->ndev->dev, "display detected\n");
 
@@ -862,6 +865,8 @@ bool tegra_dc_hdmi_detect_test(struct tegra_dc *dc, unsigned char *edid_ptr)
 #ifdef CONFIG_SWITCH
                hdmi->hpd_switch.state = 0;
                switch_set_state(&hdmi->hpd_switch, 1);
+               hdmi->audio_switch.state = 0;
+               switch_set_state(&hdmi->audio_switch, tegra_edid_audio_supported(hdmi->edid) ? 1 : 0);
 #endif
                dev_info(&dc->ndev->dev, "display detected\n");
 
@@ -884,6 +889,7 @@ fail:
        hdmi->eld_retrieved = false;
 #ifdef CONFIG_SWITCH
        switch_set_state(&hdmi->hpd_switch, 0);
+       switch_set_state(&hdmi->audio_switch, 0);
 #endif
        tegra_nvhdcp_set_plug(hdmi->nvhdcp, 0);
        return false;
@@ -917,6 +923,8 @@ static bool tegra_dc_hdmi_detect(struct tegra_dc *dc)
 #ifdef CONFIG_SWITCH
                hdmi->hpd_switch.state = 0;
                switch_set_state(&hdmi->hpd_switch, 1);
+               hdmi->audio_switch.state = 0;
+               switch_set_state(&hdmi->audio_switch, tegra_edid_audio_supported(hdmi->edid) ? 1 : 0);
 #endif
                dev_info(&dc->ndev->dev, "display detected\n");
 
@@ -948,6 +956,7 @@ fail:
        hdmi->eld_retrieved = false;
 #ifdef CONFIG_SWITCH
        switch_set_state(&hdmi->hpd_switch, 0);
+       switch_set_state(&hdmi->audio_switch, 0);
 #endif
        tegra_nvhdcp_set_plug(hdmi->nvhdcp, 0);
        return false;
@@ -1032,6 +1041,20 @@ static ssize_t underscan_show(struct device *dev,
 }
 
 static DEVICE_ATTR(underscan, S_IRUGO | S_IWUSR, underscan_show, NULL);
+
+static ssize_t hdmi_audio_show(struct device *dev,
+                               struct device_attribute *attr, char *buf)
+{
+       struct tegra_dc_hdmi_data *hdmi =
+                       container_of(dev_get_drvdata(dev), struct tegra_dc_hdmi_data, audio_switch);
+
+       if (hdmi->edid)
+               return sprintf(buf, "%d\n", tegra_edid_audio_supported(hdmi->edid));
+       else
+               return 0;
+}
+
+static DEVICE_ATTR(hdmi_audio, S_IRUGO | S_IWUSR, hdmi_audio_show, NULL);
 #endif
 
 static int tegra_dc_hdmi_init(struct tegra_dc *dc)
@@ -1167,6 +1190,14 @@ static int tegra_dc_hdmi_init(struct tegra_dc *dc)
                ret = device_create_file(hdmi->hpd_switch.dev,
                        &dev_attr_underscan);
        BUG_ON(ret != 0);
+
+       hdmi->audio_switch.name = "hdmi_audio";
+       ret = switch_dev_register(&hdmi->audio_switch);
+
+       if (!ret)
+               ret = device_create_file(hdmi->audio_switch.dev,
+                       &dev_attr_hdmi_audio);
+       BUG_ON(ret != 0);
 #endif
 
        dc->out->depth = 24;
@@ -1235,6 +1266,7 @@ static void tegra_dc_hdmi_destroy(struct tegra_dc *dc)
        cancel_delayed_work_sync(&hdmi->work);
 #ifdef CONFIG_SWITCH
        switch_dev_unregister(&hdmi->hpd_switch);
+       switch_dev_unregister(&hdmi->audio_switch);
 #endif
        iounmap(hdmi->base);
        release_resource(hdmi->base_res);