summaryrefslogtreecommitdiff
path: root/drivers/video/fbdev
diff options
context:
space:
mode:
authorUjwal Patel <ujwalp@codeaurora.org>2012-09-10 18:42:29 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:12:41 -0700
commit7473055872fe1079de54a83ef87567f96dee797b (patch)
tree39b66e6337c2176a11628e112a50131bf9179eae /drivers/video/fbdev
parentde0a2d1a22ecbda292fddcadfea6217d4f2abf8d (diff)
msm: mdss: Enable hpd for HDMI Tx controller
Enable hot-plug detect circuit of HDMI Tx controller to sense connect and disconnect events of HDMI cable. Change-Id: I4e5614d32f5c9885f23060d68ad5b6a72a045177 Signed-off-by: Ujwal Patel <ujwalp@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.c175
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_tx.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_hdmi_util.c4
3 files changed, 56 insertions, 124 deletions
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.c b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
index 3a7c2305e5e9..3fa7aa721036 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.c
@@ -189,74 +189,6 @@ static ssize_t hdmi_tx_sysfs_rda_connected(struct device *dev,
return ret;
} /* hdmi_tx_sysfs_rda_connected */
-static ssize_t hdmi_tx_sysfs_rda_fake_hpd(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- ssize_t ret;
- struct hdmi_tx_ctrl *hdmi_ctrl =
- hdmi_tx_get_drvdata_from_sysfs_dev(dev);
-
- if (!hdmi_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
- return -EINVAL;
- }
-
- mutex_lock(&hdmi_ctrl->mutex);
- ret = snprintf(buf, PAGE_SIZE, "%d\n", hdmi_ctrl->hpd_state);
- DEV_DBG("%s: '%d'\n", __func__, hdmi_ctrl->hpd_state);
- mutex_unlock(&hdmi_ctrl->mutex);
-
- return ret;
-} /* hdmi_tx_sysfs_rda_fake_hpd */
-
-static ssize_t hdmi_tx_sysfs_wta_fake_hpd(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- int fake_hpd, rc = 0;
- ssize_t ret = strnlen(buf, PAGE_SIZE);
- struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
-
- DEV_DBG("%s:\n", __func__);
- hdmi_ctrl = hdmi_tx_get_drvdata_from_sysfs_dev(dev);
-
- if (!hdmi_ctrl) {
- DEV_ERR("%s: invalid input\n", __func__);
- return -EINVAL;
- }
-
- rc = kstrtoint(buf, 10, &fake_hpd);
- if (rc) {
- DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
- return rc;
- }
-
- mutex_lock(&hdmi_ctrl->mutex);
- DEV_INFO("%s: fake_hpd=%d\n", __func__, fake_hpd);
- if (fake_hpd) {
- hdmi_ctrl->hpd_state = true;
-
- DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
- if (kobject_uevent(hdmi_ctrl->kobj, KOBJ_ONLINE))
- DEV_ERR("%s: failed sending online event\n", __func__);
- switch_set_state(&hdmi_ctrl->sdev, 1);
- DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
- hdmi_ctrl->sdev.state);
- } else {
- hdmi_ctrl->hpd_state = false;
-
- /* todo: Remove this once HPD line is available in HW */
- DEV_INFO("HDMI HPD: sense CONNECTED: send ONLINE\n");
- if (kobject_uevent(hdmi_ctrl->kobj, KOBJ_OFFLINE))
- DEV_ERR("%s: failed sending online event\n", __func__);
- switch_set_state(&hdmi_ctrl->sdev, 0);
- DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
- hdmi_ctrl->sdev.state);
- }
- mutex_unlock(&hdmi_ctrl->mutex);
-
- return ret;
-} /* hdmi_tx_sysfs_wta_fake_hpd */
-
static ssize_t hdmi_tx_sysfs_rda_hpd(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -296,16 +228,13 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev,
return rc;
}
- /* todo: Remove this once HPD line is available in HW */
- if (0) {
- if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
- rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
- } else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
- rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
- } else {
- rc = -EPERM;
- ret = rc;
- }
+ if (0 == hpd && hdmi_ctrl->hpd_feature_on) {
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, false);
+ } else if (1 == hpd && !hdmi_ctrl->hpd_feature_on) {
+ rc = hdmi_tx_sysfs_enable_hpd(hdmi_ctrl, true);
+ } else {
+ rc = -EPERM;
+ ret = rc;
}
if (!rc) {
@@ -323,13 +252,10 @@ static ssize_t hdmi_tx_sysfs_wta_hpd(struct device *dev,
static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_hpd,
hdmi_tx_sysfs_wta_hpd);
-static DEVICE_ATTR(fake_hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_fake_hpd,
- hdmi_tx_sysfs_wta_fake_hpd);
static struct attribute *hdmi_tx_fs_attrs[] = {
&dev_attr_connected.attr,
&dev_attr_hpd.attr,
- &dev_attr_fake_hpd.attr,
NULL,
};
static struct attribute_group hdmi_tx_fs_attrs_group = {
@@ -573,6 +499,45 @@ static void hdmi_tx_hpd_state_work(struct work_struct *work)
DSS_REG_W(io, HDMI_HPD_INT_CTRL, 4 | (hpd_state ? 0 : 2));
} /* hdmi_tx_hpd_state_work */
+static void hdmi_tx_hpd_int_work(struct work_struct *work)
+{
+ u32 hpd_int_status;
+ u32 hpd_int_ctrl;
+ u32 cable_detected;
+ struct hdmi_tx_ctrl *hdmi_ctrl = NULL;
+ struct dss_io_data *io = NULL;
+
+ hdmi_ctrl = container_of(work, struct hdmi_tx_ctrl, hpd_int_work);
+ if (!hdmi_ctrl || !hdmi_ctrl->hpd_initialized) {
+ DEV_DBG("%s: invalid input\n", __func__);
+ return;
+ }
+
+ io = &hdmi_ctrl->pdata.io[HDMI_TX_CORE_IO];
+ if (!io->base) {
+ DEV_ERR("%s: Core io is not initialized\n", __func__);
+ return;
+ }
+
+ /* Process HPD Interrupt */
+ hpd_int_status = DSS_REG_R(io, HDMI_HPD_INT_STATUS);
+ hpd_int_ctrl = DSS_REG_R(io, HDMI_HPD_INT_CTRL);
+
+ DSS_REG_W(io, HDMI_HPD_INT_CTRL, BIT(2));
+
+ cable_detected = hpd_int_status & BIT(1);
+ mutex_lock(&hdmi_ctrl->mutex);
+ hdmi_ctrl->hpd_cable_chg_detected = true;
+ hdmi_ctrl->hpd_prev_state = cable_detected ? 0 : 1;
+ hdmi_ctrl->hpd_stable = 0;
+ mutex_unlock(&hdmi_ctrl->mutex);
+
+ mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
+
+ DEV_DBG("%s: HPD<Ctrl=%04x, State=%04x>\n", __func__, hpd_int_ctrl,
+ hpd_int_status);
+} /* hdmi_tx_hpd_int_work */
+
static int hdmi_tx_check_capability(struct dss_io_data *io)
{
u32 hdmi_disabled, hdcp_disabled;
@@ -1193,7 +1158,6 @@ static void hdmi_tx_core_off(struct hdmi_tx_ctrl *hdmi_ctrl)
hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CEC_PM, 0);
hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 0);
- hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
} /* hdmi_tx_core_off */
static int hdmi_tx_core_on(struct hdmi_tx_ctrl *hdmi_ctrl)
@@ -1205,13 +1169,6 @@ static int hdmi_tx_core_on(struct hdmi_tx_ctrl *hdmi_ctrl)
return -EINVAL;
}
- /* todo: remove this once hpd is available */
- rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 1);
- if (rc) {
- DEV_ERR("%s: hpd hdmi_msm_enable_power failed rc = %d\n",
- __func__, rc);
- goto error;
- }
rc = hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 1);
if (rc) {
DEV_ERR("%s: core hdmi_msm_enable_power failed rc = %d\n",
@@ -1230,7 +1187,6 @@ disable_core_power:
hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_CORE_PM, 0);
disable_hpd_power:
hdmi_tx_enable_power(hdmi_ctrl, HDMI_TX_HPD_PM, 0);
-error:
return rc;
} /* hdmi_tx_core_on */
@@ -1542,7 +1498,6 @@ static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on)
rc = hdmi_tx_hpd_on(hdmi_ctrl);
} else {
hdmi_tx_hpd_off(hdmi_ctrl);
- /* Set HDMI switch node to 0 on HPD feature disable */
switch_set_state(&hdmi_ctrl->sdev, 0);
DEV_INFO("%s: Hdmi state switch to %d\n", __func__,
hdmi_ctrl->sdev.state);
@@ -1553,8 +1508,6 @@ static int hdmi_tx_sysfs_enable_hpd(struct hdmi_tx_ctrl *hdmi_ctrl, int on)
static irqreturn_t hdmi_tx_isr(int irq, void *data)
{
- u32 hpd_int_status;
- u32 hpd_int_ctrl;
struct dss_io_data *io = NULL;
struct hdmi_tx_ctrl *hdmi_ctrl = (struct hdmi_tx_ctrl *)data;
@@ -1570,38 +1523,17 @@ static irqreturn_t hdmi_tx_isr(int irq, void *data)
return IRQ_HANDLED;
}
- /* Process HPD Interrupt */
- hpd_int_status = DSS_REG_R(io, HDMI_HPD_INT_STATUS);
- hpd_int_ctrl = DSS_REG_R(io, HDMI_HPD_INT_CTRL);
- if ((hpd_int_ctrl & BIT(2)) && (hpd_int_status & BIT(0))) {
- u32 cable_detected = hpd_int_status & BIT(1);
-
+ if (DSS_REG_R(io, HDMI_HPD_INT_STATUS) & BIT(0)) {
/*
- * Clear all interrupts, timer will turn IRQ back on
- * Leaving the bit[2] on, else core goes off
- * on getting HPD during power off.
+ * Turn off HPD irq and clear all interrupts,
+ * worker will turn IRQ back on
*/
- DSS_REG_W(io, HDMI_HPD_INT_CTRL, BIT(2) | BIT(0));
-
- DEV_DBG("%s: HPD IRQ, Ctrl=%04x, State=%04x\n", __func__,
- hpd_int_ctrl, hpd_int_status);
-
- mutex_lock(&hdmi_ctrl->mutex);
- hdmi_ctrl->hpd_cable_chg_detected = true;
- hdmi_ctrl->hpd_prev_state = cable_detected ? 0 : 1;
- hdmi_ctrl->hpd_stable = 0;
- mutex_unlock(&hdmi_ctrl->mutex);
-
- mod_timer(&hdmi_ctrl->hpd_state_timer, jiffies + HZ/2);
-
- return IRQ_HANDLED;
+ DSS_REG_W(io, HDMI_HPD_INT_CTRL, ~BIT(2) | BIT(0));
+ queue_work(hdmi_ctrl->workq, &hdmi_ctrl->hpd_int_work);
}
- if (!hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl))
- return IRQ_HANDLED;
-
- DEV_DBG("%s: HPD<Ctrl=%04x, State=%04x>\n", __func__, hpd_int_ctrl,
- hpd_int_status);
+ if (hdmi_ddc_isr(&hdmi_ctrl->ddc_ctrl) < 0)
+ DEV_ERR("%s: hdmi_ddc_isr failed\n", __func__);
return IRQ_HANDLED;
} /* hdmi_tx_isr */
@@ -1658,6 +1590,7 @@ static int hdmi_tx_dev_init(struct hdmi_tx_ctrl *hdmi_ctrl)
init_completion(&hdmi_ctrl->ddc_ctrl.ddc_sw_done);
INIT_WORK(&hdmi_ctrl->hpd_state_work, hdmi_tx_hpd_state_work);
+ INIT_WORK(&hdmi_ctrl->hpd_int_work, hdmi_tx_hpd_int_work);
init_timer(&hdmi_ctrl->hpd_state_timer);
hdmi_ctrl->hpd_state_timer.function = hdmi_tx_hpd_state_timer;
hdmi_ctrl->hpd_state_timer.data = (u32)hdmi_ctrl;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_tx.h b/drivers/video/fbdev/msm/mdss_hdmi_tx.h
index 6eaf3c375c6a..dd54d9b210e4 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_tx.h
+++ b/drivers/video/fbdev/msm/mdss_hdmi_tx.h
@@ -56,6 +56,7 @@ struct hdmi_tx_ctrl {
u32 hpd_state;
u32 hpd_feature_on;
struct work_struct hpd_state_work;
+ struct work_struct hpd_int_work;
struct timer_list hpd_state_timer;
unsigned long pixel_clk;
diff --git a/drivers/video/fbdev/msm/mdss_hdmi_util.c b/drivers/video/fbdev/msm/mdss_hdmi_util.c
index 136f0ec2bd9c..55182a24a660 100644
--- a/drivers/video/fbdev/msm/mdss_hdmi_util.c
+++ b/drivers/video/fbdev/msm/mdss_hdmi_util.c
@@ -505,7 +505,6 @@ void hdmi_ddc_config(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
{
- int rc = -1;
u32 ddc_int_ctrl;
if (!ddc_ctrl || !ddc_ctrl->io) {
@@ -519,12 +518,11 @@ int hdmi_ddc_isr(struct hdmi_tx_ddc_ctrl *ddc_ctrl)
DSS_REG_W_ND(ddc_ctrl->io, HDMI_DDC_INT_CTRL,
ddc_int_ctrl | BIT(1));
complete(&ddc_ctrl->ddc_sw_done);
- return 0;
}
DEV_DBG("%s: ddc_int_ctrl=%04x\n", __func__, ddc_int_ctrl);
- return rc;
+ return 0;
} /* hdmi_ddc_isr */
int hdmi_ddc_read(struct hdmi_tx_ddc_ctrl *ddc_ctrl,