Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 97870d15 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: hdmi: add audio notification acknowledge feature"

parents fe0c18f1 258dad75
Loading
Loading
Loading
Loading
+98 −3
Original line number Diff line number Diff line
@@ -47,6 +47,10 @@
#define HPD_DISCONNECT_POLARITY 0
#define HPD_CONNECT_POLARITY    1

#define AUDIO_ACK_SET_ENABLE BIT(5)
#define AUDIO_ACK_ENABLE BIT(4)
#define AUDIO_ACK_CONNECT BIT(0)

/*
 * Audio engine may take 1 to 3 sec to shutdown
 * in normal cases. To handle worst cases, making
@@ -522,15 +526,29 @@ static inline void hdmi_tx_set_audio_switch_node(
		DEV_ERR("%s: invalid input\n", __func__);
		return;
	}

	state = hdmi_ctrl->audio_sdev.state;

	if (hdmi_ctrl->audio_ack_enabled &&
		atomic_read(&hdmi_ctrl->audio_ack_pending)) {
		DEV_ERR("%s: %s ack pending, not notifying %s\n", __func__,
			state ? "connect" : "disconnect",
			val ? "connect" : "disconnect");
		return;
	}

	if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) &&
	    hdmi_tx_is_cea_format(hdmi_ctrl->vid_cfg.vic)) {
		bool switched;

		switch_set_state(&hdmi_ctrl->audio_sdev, val);
		switched = hdmi_ctrl->audio_sdev.state != state;

		if (hdmi_ctrl->audio_ack_enabled && switched)
			atomic_set(&hdmi_ctrl->audio_ack_pending, 1);

		DEV_INFO("%s: audio state %s %d\n", __func__,
			hdmi_ctrl->audio_sdev.state == state ?
				"is same" : "switched to",
			switched ? "switched to" : "is same",
			hdmi_ctrl->audio_sdev.state);
	}
} /* hdmi_tx_set_audio_switch_node */
@@ -649,6 +667,54 @@ static ssize_t hdmi_tx_sysfs_rda_connected(struct device *dev,
	return ret;
} /* hdmi_tx_sysfs_rda_connected */

static ssize_t hdmi_tx_sysfs_wta_audio_cb(struct device *dev,
	struct device_attribute *attr, const char *buf, size_t count)
{
	int ack, rc = 0;
	int ack_hpd;
	ssize_t ret = strnlen(buf, PAGE_SIZE);
	struct hdmi_tx_ctrl *hdmi_ctrl = NULL;

	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, &ack);
	if (rc) {
		DEV_ERR("%s: kstrtoint failed. rc=%d\n", __func__, rc);
		return rc;
	}

	if (ack & AUDIO_ACK_SET_ENABLE) {
		hdmi_ctrl->audio_ack_enabled = ack & AUDIO_ACK_ENABLE ?
			true : false;

		DEV_INFO("%s: audio ack feature %s\n", __func__,
			hdmi_ctrl->audio_ack_enabled ? "enabled" : "disabled");

		return ret;
	}

	if (!hdmi_ctrl->audio_ack_enabled)
		return ret;

	atomic_set(&hdmi_ctrl->audio_ack_pending, 0);

	ack_hpd = ack & AUDIO_ACK_CONNECT;

	if (ack_hpd != hdmi_ctrl->hpd_state) {
		DEV_INFO("%s: unbalanced audio state, ack %d, hpd %d\n",
			__func__, ack_hpd, hdmi_ctrl->hpd_state);

		hdmi_tx_set_audio_switch_node(hdmi_ctrl, hdmi_ctrl->hpd_state);
	}

	return ret;
}

static ssize_t hdmi_tx_sysfs_rda_video_mode(struct device *dev,
	struct device_attribute *attr, char *buf)
{
@@ -989,6 +1055,7 @@ static ssize_t hdmi_tx_sysfs_wta_avi_cn_bits(struct device *dev,
} /* hdmi_tx_sysfs_wta_cn_bits */

static DEVICE_ATTR(connected, S_IRUGO, hdmi_tx_sysfs_rda_connected, NULL);
static DEVICE_ATTR(hdmi_audio_cb, S_IWUSR, NULL, hdmi_tx_sysfs_wta_audio_cb);
static DEVICE_ATTR(video_mode, S_IRUGO, hdmi_tx_sysfs_rda_video_mode, NULL);
static DEVICE_ATTR(hpd, S_IRUGO | S_IWUSR, hdmi_tx_sysfs_rda_hpd,
	hdmi_tx_sysfs_wta_hpd);
@@ -1002,6 +1069,7 @@ static DEVICE_ATTR(avi_cn0_1, S_IWUSR, NULL, hdmi_tx_sysfs_wta_avi_cn_bits);

static struct attribute *hdmi_tx_fs_attrs[] = {
	&dev_attr_connected.attr,
	&dev_attr_hdmi_audio_cb.attr,
	&dev_attr_video_mode.attr,
	&dev_attr_hpd.attr,
	&dev_attr_vendor_name.attr,
@@ -2654,14 +2722,17 @@ static int hdmi_tx_audio_info_setup(struct platform_device *pdev,
{
	int rc = 0;
	struct hdmi_tx_ctrl *hdmi_ctrl = platform_get_drvdata(pdev);
	u32 is_mode_dvi;

	if (!hdmi_ctrl) {
		DEV_ERR("%s: invalid input\n", __func__);
		return -ENODEV;
	}

	is_mode_dvi = hdmi_tx_is_dvi_mode(hdmi_ctrl);

	mutex_lock(&hdmi_ctrl->power_mutex);
	if (!hdmi_tx_is_dvi_mode(hdmi_ctrl) && hdmi_ctrl->panel_power_on) {
	if (!is_mode_dvi && hdmi_ctrl->panel_power_on) {
		mutex_unlock(&hdmi_ctrl->power_mutex);
		/* Map given sample rate to Enum */
		if (sample_rate == 32000)
@@ -2694,6 +2765,15 @@ static int hdmi_tx_audio_info_setup(struct platform_device *pdev,
		rc = -EPERM;
	}

	if (rc)
		dev_err_ratelimited(&hdmi_ctrl->pdev->dev,
			"%s: hpd %d, ack %d, switch %d, mode %s, power %d\n",
			__func__, hdmi_ctrl->hpd_state,
			atomic_read(&hdmi_ctrl->audio_ack_pending),
			hdmi_ctrl->audio_sdev.state,
			is_mode_dvi ? "dvi" : "hdmi",
			hdmi_ctrl->panel_power_on);

	return rc;
} /* hdmi_tx_audio_info_setup */

@@ -2792,6 +2872,19 @@ static int hdmi_tx_get_cable_status(struct platform_device *pdev, u32 vote)
	if (vote && hpd)
		hdmi_ctrl->vote_hdmi_core_on = true;

	/*
	 * if cable is not connected and audio calls this function,
	 * consider this as an error as it will result in whole
	 * audio path to fail.
	 */
	if (!hpd)
		dev_err_ratelimited(&hdmi_ctrl->pdev->dev,
			"%s: hpd %d, ack %d, switch %d, power %d\n",
			__func__, hdmi_ctrl->hpd_state,
			atomic_read(&hdmi_ctrl->audio_ack_pending),
			hdmi_ctrl->audio_sdev.state,
			hdmi_ctrl->panel_power_on);

	return hpd;
}

@@ -3372,6 +3465,8 @@ static int hdmi_tx_hpd_on(struct hdmi_tx_ctrl *hdmi_ctrl)
		/* Turn on HPD HW circuit */
		DSS_REG_W(io, HDMI_HPD_CTRL, reg_val | BIT(28));

		atomic_set(&hdmi_ctrl->audio_ack_pending, 0);

		hdmi_tx_hpd_polarity_setup(hdmi_ctrl, HPD_CONNECT_POLARITY);
		DEV_DBG("%s: HPD is now ON\n", __func__);
	}
+2 −0
Original line number Diff line number Diff line
@@ -171,6 +171,8 @@ struct hdmi_tx_ctrl {
	bool hpd_disabled;
	bool ds_registered;
	u32 hdcp14_present;
	bool audio_ack_enabled;
	atomic_t audio_ack_pending;

	u8 spd_vendor_name[9];
	u8 spd_product_description[17];