msm: mdss: dp: fix audio teardown sequence

First update the audio switch node to indicate that the cable was
disconnected. Wait for the audio codec to indicate that the teardown
of the audio path has been completed, timing out after three
seconds. This ensures that the audio framework will start and end
the audio teardown while the interface VSync is still running,
ensuring a graceful shutdown of the audio path.

CRs-Fixed: 1074218
Change-Id: Ia9c792613e5cd9ac273185c6b2f4b30b5df67496
Signed-off-by: Tatenda Chipeperekwa <tatendac@codeaurora.org>
This commit is contained in:
Tatenda Chipeperekwa 2016-09-29 18:34:22 -07:00 committed by Gerrit - the friendly Code Review server
parent 3c7400dc73
commit 0cfcf4427c
4 changed files with 82 additions and 12 deletions

View file

@ -863,6 +863,8 @@ static int dp_audio_info_setup(struct platform_device *pdev,
mdss_dp_set_safe_to_exit_level(&dp_ctrl->ctrl_io, dp_ctrl->lane_cnt);
mdss_dp_audio_enable(&dp_ctrl->ctrl_io, true);
dp_ctrl->wait_for_audio_comp = true;
return rc;
} /* dp_audio_info_setup */
@ -885,6 +887,17 @@ static int dp_get_audio_edid_blk(struct platform_device *pdev,
return rc;
} /* dp_get_audio_edid_blk */
static void dp_audio_codec_teardown_done(struct platform_device *pdev)
{
struct mdss_dp_drv_pdata *dp = platform_get_drvdata(pdev);
if (!dp)
pr_err("invalid input\n");
pr_debug("audio codec teardown done\n");
complete_all(&dp->audio_comp);
}
static int mdss_dp_init_ext_disp(struct mdss_dp_drv_pdata *dp)
{
int ret = 0;
@ -906,6 +919,8 @@ static int mdss_dp_init_ext_disp(struct mdss_dp_drv_pdata *dp)
dp_get_audio_edid_blk;
dp->ext_audio_data.codec_ops.cable_status =
dp_get_cable_status;
dp->ext_audio_data.codec_ops.teardown_done =
dp_audio_codec_teardown_done;
if (!dp->pdev->dev.of_node) {
pr_err("%s cannot find dp dev.of_node\n", __func__);
@ -987,6 +1002,13 @@ static int dp_init_panel_info(struct mdss_dp_drv_pdata *dp_drv, u32 vic)
return 0;
} /* dp_init_panel_info */
static inline void mdss_dp_set_audio_switch_node(
struct mdss_dp_drv_pdata *dp, int val)
{
if (dp && dp->ext_audio_data.intf_ops.notify)
dp->ext_audio_data.intf_ops.notify(dp->ext_pdev,
val);
}
int mdss_dp_on(struct mdss_panel_data *pdata)
{
@ -1096,6 +1118,7 @@ int mdss_dp_on(struct mdss_panel_data *pdata)
pr_debug("mainlink ready\n");
dp_drv->power_on = true;
mdss_dp_set_audio_switch_node(dp_drv, true);
pr_debug("End-\n");
exit:
@ -1127,6 +1150,8 @@ int mdss_dp_off(struct mdss_panel_data *pdata)
mdss_dp_aux_ctrl(&dp_drv->ctrl_io, false);
mdss_dp_audio_enable(&dp_drv->ctrl_io, false);
mdss_dp_irq_disable(dp_drv);
mdss_dp_config_gpios(dp_drv, false);
@ -1147,14 +1172,6 @@ int mdss_dp_off(struct mdss_panel_data *pdata)
return 0;
}
static inline void mdss_dp_set_audio_switch_node(
struct mdss_dp_drv_pdata *dp, int val)
{
if (dp && dp->ext_audio_data.intf_ops.notify)
dp->ext_audio_data.intf_ops.notify(dp->ext_pdev,
val);
}
static void mdss_dp_send_cable_notification(
struct mdss_dp_drv_pdata *dp, int val)
{
@ -1169,6 +1186,38 @@ static void mdss_dp_send_cable_notification(
dp->ext_audio_data.type, val);
}
static void mdss_dp_audio_codec_wait(struct mdss_dp_drv_pdata *dp)
{
const int audio_completion_timeout_ms = HZ * 3;
int ret = 0;
if (!dp->wait_for_audio_comp)
return;
reinit_completion(&dp->audio_comp);
ret = wait_for_completion_timeout(&dp->audio_comp,
audio_completion_timeout_ms);
if (ret <= 0)
pr_warn("audio codec teardown timed out\n");
dp->wait_for_audio_comp = false;
}
static void mdss_dp_notify_clients(struct mdss_dp_drv_pdata *dp, bool enable)
{
if (enable) {
mdss_dp_send_cable_notification(dp, enable);
} else {
mdss_dp_set_audio_switch_node(dp, enable);
mdss_dp_audio_codec_wait(dp);
mdss_dp_send_cable_notification(dp, enable);
}
pr_debug("notify state %s done\n",
enable ? "ENABLE" : "DISABLE");
}
static int mdss_dp_edid_init(struct mdss_panel_data *pdata)
{
struct mdss_dp_drv_pdata *dp_drv = NULL;
@ -1264,8 +1313,7 @@ static int mdss_dp_host_init(struct mdss_panel_data *pdata)
goto edid_error;
}
mdss_dp_send_cable_notification(dp_drv, true);
mdss_dp_set_audio_switch_node(dp_drv, true);
mdss_dp_notify_clients(dp_drv, true);
dp_drv->dp_initialized = true;
return ret;
@ -1883,8 +1931,7 @@ static void usbpd_disconnect_callback(struct usbpd_svid_handler *hdlr)
mutex_lock(&dp_drv->pd_msg_mutex);
dp_drv->cable_connected = false;
mutex_unlock(&dp_drv->pd_msg_mutex);
mdss_dp_send_cable_notification(dp_drv, false);
mdss_dp_set_audio_switch_node(dp_drv, false);
mdss_dp_notify_clients(dp_drv, false);
}
static void usbpd_response_callback(struct usbpd_svid_handler *hdlr, u8 cmd,
@ -2135,6 +2182,8 @@ static int mdss_dp_probe(struct platform_device *pdev)
mdss_dp_device_register(dp_drv);
dp_drv->inited = true;
dp_drv->wait_for_audio_comp = false;
init_completion(&dp_drv->audio_comp);
pr_debug("done\n");

View file

@ -399,6 +399,7 @@ struct mdss_dp_drv_pdata {
struct completion train_comp;
struct completion idle_comp;
struct completion video_comp;
struct completion audio_comp;
struct mutex aux_mutex;
struct mutex train_mutex;
struct mutex pd_msg_mutex;
@ -423,6 +424,7 @@ struct mdss_dp_drv_pdata {
char delay_start;
u32 bpp;
struct dp_statistic dp_stat;
bool wait_for_audio_comp;
/* event */
struct workqueue_struct *workq;

View file

@ -365,6 +365,7 @@ static int msm_ext_disp_hpd(struct platform_device *pdev,
ext_disp->ops->get_audio_edid_blk = NULL;
ext_disp->ops->cable_status = NULL;
ext_disp->ops->get_intf_id = NULL;
ext_disp->ops->teardown_done = NULL;
}
ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;
@ -463,6 +464,20 @@ end:
return ret;
}
static void msm_ext_disp_teardown_done(struct platform_device *pdev)
{
int ret = 0;
struct msm_ext_disp_init_data *data = NULL;
ret = msm_ext_disp_get_intf_data_helper(pdev, &data);
if (ret || !data) {
pr_err("invalid input");
return;
}
data->codec_ops.teardown_done(data->pdev);
}
static int msm_ext_disp_get_intf_id(struct platform_device *pdev)
{
int ret = 0;
@ -545,6 +560,8 @@ static int msm_ext_disp_notify(struct platform_device *pdev,
msm_ext_disp_cable_status;
ext_disp->ops->get_intf_id =
msm_ext_disp_get_intf_id;
ext_disp->ops->teardown_done =
msm_ext_disp_teardown_done;
}
switch_set_state(&ext_disp->audio_sdev, (int)new_state);
@ -614,6 +631,7 @@ static int msm_ext_disp_audio_ack(struct platform_device *pdev, u32 ack)
ext_disp->ops->get_audio_edid_blk = NULL;
ext_disp->ops->cable_status = NULL;
ext_disp->ops->get_intf_id = NULL;
ext_disp->ops->teardown_done = NULL;
}
ext_disp->current_disp = EXT_DISPLAY_TYPE_MAX;

View file

@ -108,6 +108,7 @@ struct msm_ext_disp_audio_codec_ops {
struct msm_ext_disp_audio_edid_blk *blk);
int (*cable_status)(struct platform_device *pdev, u32 vote);
int (*get_intf_id)(struct platform_device *pdev);
void (*teardown_done)(struct platform_device *pdev);
};
/*