msm: adv7533: check for HPD interrupt during power on

Since adv7533 interrupt is edge triggered, if cable is
already connected during power on sequence, then it won't
trigger HPD interrupt. When display framework probes for
HDP on external display, explicitly check if cable is
connected and send notification if EDID is read successfully.

Change-Id: Ia1a660f40c86a900ba387afa0615022859cce6f5
Signed-off-by: Sandeep Panda <spanda@codeaurora.org>
This commit is contained in:
Sandeep Panda 2015-07-12 17:33:40 +05:30 committed by Gerrit - the friendly Code Review server
parent b2fd756bae
commit 2e8a47fca2
3 changed files with 82 additions and 19 deletions

View File

@ -155,11 +155,47 @@ static ssize_t mdss_dba_utils_sysfs_rda_connected(struct device *dev,
return ret;
}
static ssize_t mdss_dba_utils_sysfs_wta_hpd(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct mdss_dba_utils_data *udata = NULL;
int rc, hpd;
udata = mdss_dba_utils_get_data(dev);
if (!udata) {
pr_debug("%s: invalid input\n", __func__);
return -EINVAL;
}
rc = kstrtoint(buf, 10, &hpd);
if (rc) {
pr_debug("%s: kstrtoint failed\n", __func__);
return -EINVAL;
}
if (!hpd || udata->hpd_state)
return count;
/* power on downstream device */
if (udata->ops.power_on)
udata->ops.power_on(udata->dba_data, true, 0);
/* check if cable is connected to bridge chip */
if (udata->ops.check_hpd)
udata->ops.check_hpd(udata->dba_data, 0);
return count;
}
static DEVICE_ATTR(connected, S_IRUGO,
mdss_dba_utils_sysfs_rda_connected, NULL);
static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, NULL,
mdss_dba_utils_sysfs_wta_hpd);
static struct attribute *mdss_dba_utils_fs_attrs[] = {
&dev_attr_connected.attr,
&dev_attr_hpd.attr,
NULL,
};
@ -341,18 +377,8 @@ static int mdss_dba_utils_init_switch_dev(struct mdss_dba_utils_data *udata,
goto end;
}
pr_debug("fb_node %d\n", fb_node);
ret = snprintf(udata->disp_switch_name,
sizeof(udata->disp_switch_name),
"fb%d", fb_node);
if (!ret) {
DEV_ERR("%s: couldn't write display switch node\n", __func__);
goto end;
}
/* create switch device to update display modules */
udata->sdev_display.name = udata->disp_switch_name;
udata->sdev_display.name = "hdmi";
rc = switch_dev_register(&udata->sdev_display);
if (rc) {
pr_err("display switch registration failed\n");
@ -564,13 +590,6 @@ void *mdss_dba_utils_init(struct mdss_dba_utils_init_data *uid)
uid->pinfo->is_pluggable = true;
}
/* power on downstream device */
if (udata->ops.power_on) {
ret = udata->ops.power_on(udata->dba_data, true, 0);
if (ret)
goto error;
}
return udata;
error:

View File

@ -155,6 +155,7 @@ struct adv7533 {
struct dss_module_power power_data;
bool hdcp_enabled;
bool cec_enabled;
bool is_power_on;
void *edid_data;
u8 edid_buf[EDID_SEG_SIZE];
struct workqueue_struct *workq;
@ -1121,6 +1122,43 @@ end:
return ret;
}
static int adv7533_check_hpd(void *client, u32 flags)
{
int ret = -EINVAL;
struct adv7533 *pdata = adv7533_get_platform_data(client);
u8 reg_val = 0;
u8 intr_status;
int connected = 0;
if (!pdata) {
pr_err("%s: invalid platform data\n", __func__);
return ret;
}
/* Check if cable is already connected.
* Since adv7533_irq line is edge triggered,
* if cable is already connected by this time
* it won't trigger HPD interrupt.
*/
mutex_lock(&pdata->ops_mutex);
ADV7533_READ(I2C_ADDR_MAIN, 0x42, &reg_val, 1);
connected = (reg_val & BIT(6));
if (connected) {
pr_debug("%s: cable is connected\n", __func__);
/* Clear the interrupts before initiating EDID read */
ADV7533_READ(I2C_ADDR_MAIN, 0x96, &intr_status, 1);
ADV7533_WRITE(I2C_ADDR_MAIN, 0x96, intr_status);
adv7533_enable_interrupts(pdata, (CFG_EDID_INTERRUPTS |
CFG_HPD_INTERRUPTS));
adv7533_edid_read_init(pdata);
}
end:
mutex_unlock(&pdata->ops_mutex);
return connected;
}
/* Device Operations */
static int adv7533_power_on(void *client, bool on, u32 flags)
{
@ -1134,7 +1172,7 @@ static int adv7533_power_on(void *client, bool on, u32 flags)
mutex_lock(&pdata->ops_mutex);
if (on) {
if (on && !pdata->is_power_on) {
ADV7533_WRITE_ARRAY(adv7533_init_setup);
ret = adv7533_enable_interrupts(pdata, CFG_HPD_INTERRUPTS);
@ -1143,9 +1181,11 @@ static int adv7533_power_on(void *client, bool on, u32 flags)
__func__, ret);
goto end;
}
pdata->is_power_on = true;
} else {
/* power down hdmi */
ADV7533_WRITE(I2C_ADDR_MAIN, 0x41, 0x50);
pdata->is_power_on = false;
}
end:
mutex_unlock(&pdata->ops_mutex);
@ -1586,6 +1626,7 @@ static int adv7533_register_dba(struct adv7533 *pdata)
client_ops->hdmi_cec_read = adv7533_hdmi_cec_read;
client_ops->get_edid_size = adv7533_get_edid_size;
client_ops->get_raw_edid = adv7533_get_raw_edid;
client_ops->check_hpd = adv7533_check_hpd;
dev_ops->write_reg = adv7533_write_reg;
dev_ops->read_reg = adv7533_read_reg;

View File

@ -463,6 +463,8 @@ struct msm_dba_video_cfg {
* have been applied so far after the reset is complete. In case
* of multiple clients, driver will issue a reset callback.
* @dump_debug_info: dumps debug information to dmesg.
* @check_hpd: Check if cable is connected or not. if cable is connected we
* send notification to display framework.
*
* The msm_dba_ops structure represents a set of operations that can be
* supported by each bridge chip. Depending on the functionality supported by a
@ -560,6 +562,7 @@ struct msm_dba_ops {
int (*force_reset)(void *client, u32 flags);
int (*dump_debug_info)(void *client, u32 flags);
int (*check_hpd)(void *client, u32 flags);
};
/**