Merge "msm: mdss: hdmi: HDMI cable connection status and vote"
diff --git a/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h b/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h
index ff3da11..3973044 100644
--- a/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h
+++ b/arch/arm/mach-msm/include/mach/msm_hdmi_audio_codec.h
@@ -30,6 +30,7 @@
bool down_mix);
int (*get_audio_edid_blk) (struct platform_device *pdev,
struct msm_hdmi_audio_edid_blk *blk);
+ int (*hdmi_cable_status) (struct platform_device *pdev, u32 vote);
};
int msm_hdmi_register_audio_codec(struct platform_device *pdev,
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.c b/drivers/video/msm/mdss/mdss_hdmi_tx.c
index e46e361..0cd0543 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.c
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.c
@@ -372,6 +372,7 @@
static void hdmi_tx_wait_for_audio_engine(struct hdmi_tx_ctrl *hdmi_ctrl)
{
u32 status = 0;
+ u32 wait_for_vote = 50;
struct dss_io_data *io = NULL;
if (!hdmi_ctrl) {
@@ -385,6 +386,18 @@
return;
}
+ /*
+ * wait for 5 sec max for audio engine to acknowledge if hdmi tx core
+ * can be safely turned off. Sleep for a reasonable time to make sure
+ * vote_hdmi_core_on variable is updated properly by audio.
+ */
+ while (hdmi_ctrl->vote_hdmi_core_on && --wait_for_vote)
+ msleep(100);
+
+
+ if (!wait_for_vote)
+ DEV_ERR("%s: HDMI core still voted for power on\n", __func__);
+
if (readl_poll_timeout(io->base + HDMI_AUDIO_PKT_CTRL, status,
(status & BIT(0)) == 0, AUDIO_POLL_SLEEP_US,
AUDIO_POLL_TIMEOUT_US))
@@ -2238,6 +2251,29 @@
return 0;
}
+static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote)
+{
+ struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
+ unsigned long flags;
+ u32 hpd;
+
+ if (!hdmi_ctrl) {
+ DEV_ERR("%s: invalid input\n", __func__);
+ return -ENODEV;
+ }
+
+ spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags);
+ hpd = hdmi_ctrl->hpd_state;
+ spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags);
+
+ hdmi_ctrl->vote_hdmi_core_on = false;
+
+ if (vote && hpd)
+ hdmi_ctrl->vote_hdmi_core_on = true;
+
+ return hpd;
+}
+
int msm_hdmi_register_audio_codec(struct platform_device *pdev,
struct msm_hdmi_audio_codec_ops *ops)
{
@@ -2250,6 +2286,7 @@
ops->audio_info_setup = hdmi_tx_audio_info_setup;
ops->get_audio_edid_blk = hdmi_tx_get_audio_edid_blk;
+ ops->hdmi_cable_status = hdmi_tx_get_cable_status;
return 0;
} /* hdmi_tx_audio_register */
@@ -2565,6 +2602,7 @@
{
int rc = 0;
struct dss_io_data *io = NULL;
+ unsigned long flags;
if (!hdmi_ctrl) {
DEV_ERR("%s: invalid input\n", __func__);
@@ -2604,7 +2642,10 @@
DEV_INFO("%s: Failed to disable hpd power. Error=%d\n",
__func__, rc);
+ spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags);
hdmi_ctrl->hpd_state = false;
+ spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags);
+
hdmi_ctrl->hpd_initialized = false;
} /* hdmi_tx_hpd_off */
@@ -2730,6 +2771,7 @@
{
struct dss_io_data *io = NULL;
struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
+ unsigned long flags;
if (!hdmi_ctrl) {
DEV_WARN("%s: invalid input data, ISR ignored\n", __func__);
@@ -2744,8 +2786,10 @@
}
if (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(0)) {
+ spin_lock_irqsave(&hdmi_ctrl->hpd_state_lock, flags);
hdmi_ctrl->hpd_state =
(DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(1)) >> 1;
+ spin_unlock_irqrestore(&hdmi_ctrl->hpd_state_lock, flags);
/*
* Ack the current hpd interrupt and stop listening to
@@ -2844,6 +2888,8 @@
INIT_WORK(&hdmi_ctrl->power_off_work, hdmi_tx_power_off_work);
+ spin_lock_init(&hdmi_ctrl->hpd_state_lock);
+
hdmi_ctrl->audio_data.sample_rate = AUDIO_SAMPLE_RATE_48KHZ;
hdmi_ctrl->audio_data.channel_num = MSM_HDMI_AUDIO_CHANNEL_2;
diff --git a/drivers/video/msm/mdss/mdss_hdmi_tx.h b/drivers/video/msm/mdss/mdss_hdmi_tx.h
index fd95582..5f2a23e 100644
--- a/drivers/video/msm/mdss/mdss_hdmi_tx.h
+++ b/drivers/video/msm/mdss/mdss_hdmi_tx.h
@@ -58,6 +58,7 @@
struct switch_dev sdev;
struct switch_dev audio_sdev;
struct workqueue_struct *workq;
+ spinlock_t hpd_state_lock;
uint32_t video_resolution;
@@ -68,6 +69,7 @@
u32 hpd_off_pending;
u32 hpd_feature_on;
u32 hpd_initialized;
+ u32 vote_hdmi_core_on;
u8 timing_gen_on;
u32 mhl_max_pclk;
u8 mhl_hpd_on;