@ -20,6 +20,7 @@
# include <linux/debugfs.h>
# include <linux/component.h>
# include <linux/of_irq.h>
# include <linux/extcon.h>
# include <linux/soc/qcom/fsa4480-i2c.h>
# include "sde_connector.h"
@ -107,6 +108,8 @@ struct dp_display_private {
u32 active_stream_cnt ;
struct dp_mst mst ;
struct notifier_block usb_nb ;
} ;
static const struct of_device_id dp_dt_match [ ] = {
@ -556,6 +559,9 @@ static int dp_display_send_hpd_notification(struct dp_display_private *dp)
if ( hpd & & dp - > mst . mst_active )
goto skip_wait ;
if ( ! dp - > mst . mst_active & & ( dp - > power_on = = hpd ) )
goto skip_wait ;
if ( ! wait_for_completion_timeout ( & dp - > notification_comp ,
HZ * timeout_sec ) ) {
pr_warn ( " %s timeout \n " , hpd ? " connect " : " disconnect " ) ;
@ -816,6 +822,24 @@ static int dp_display_handle_disconnect(struct dp_display_private *dp)
return rc ;
}
static void dp_display_disconnect_sync ( struct dp_display_private * dp )
{
/* cancel any pending request */
atomic_set ( & dp - > aborted , 1 ) ;
dp - > ctrl - > abort ( dp - > ctrl ) ;
dp - > aux - > abort ( dp - > aux ) ;
/* wait for idle state */
cancel_delayed_work ( & dp - > connect_work ) ;
cancel_work ( & dp - > attention_work ) ;
flush_workqueue ( dp - > wq ) ;
dp_display_handle_disconnect ( dp ) ;
/* Reset abort value to allow future connections */
atomic_set ( & dp - > aborted , 0 ) ;
}
static int dp_display_usbpd_disconnect_cb ( struct device * dev )
{
int rc = 0 ;
@ -844,21 +868,7 @@ static int dp_display_usbpd_disconnect_cb(struct device *dev)
if ( dp - > debug - > psm_enabled )
dp - > link - > psm_config ( dp - > link , & dp - > panel - > link_info , true ) ;
/* cancel any pending request */
atomic_set ( & dp - > aborted , 1 ) ;
dp - > ctrl - > abort ( dp - > ctrl ) ;
dp - > aux - > abort ( dp - > aux ) ;
/* wait for idle state */
cancel_delayed_work ( & dp - > connect_work ) ;
cancel_work ( & dp - > attention_work ) ;
flush_workqueue ( dp - > wq ) ;
dp_display_handle_disconnect ( dp ) ;
/* Reset abort value to allow future connections */
atomic_set ( & dp - > aborted , 0 ) ;
dp_display_disconnect_sync ( dp ) ;
dp - > dp_display . post_open = NULL ;
end :
return rc ;
@ -976,29 +986,14 @@ static int dp_display_usbpd_attention_cb(struct device *dev)
dp - > hpd - > hpd_irq , dp - > hpd - > hpd_high ,
dp - > power_on ) ;
if ( ! dp - > hpd - > hpd_high ) {
if ( ! dp - > is_connected ) {
pr_debug ( " already disconnected \n " ) ;
return 0 ;
}
/* cancel any pending request */
atomic_set ( & dp - > aborted , 1 ) ;
dp - > ctrl - > abort ( dp - > ctrl ) ;
dp - > aux - > abort ( dp - > aux ) ;
/* wait for idle state */
cancel_delayed_work ( & dp - > connect_work ) ;
cancel_work ( & dp - > attention_work ) ;
flush_workqueue ( dp - > wq ) ;
dp_display_handle_disconnect ( dp ) ;
atomic_set ( & dp - > aborted , 0 ) ;
} else if ( dp - > hpd - > hpd_irq & & dp - > core_initialized ) {
if ( ! dp - > hpd - > hpd_high )
dp_display_disconnect_sync ( dp ) ;
else if ( dp - > hpd - > hpd_irq & & dp - > core_initialized )
queue_work ( dp - > wq , & dp - > attention_work ) ;
} else {
else if ( ! dp - > power_on )
queue_delayed_work ( dp - > wq , & dp - > connect_work , 0 ) ;
}
else
pr_debug ( " ignored \n " ) ;
return 0 ;
}
@ -1026,6 +1021,41 @@ static void dp_display_connect_work(struct work_struct *work)
dp - > link - > send_test_response ( dp - > link ) ;
}
static int dp_display_usb_notifier ( struct notifier_block * nb ,
unsigned long event , void * ptr )
{
struct extcon_dev * edev = ptr ;
struct dp_display_private * dp = container_of ( nb ,
struct dp_display_private , usb_nb ) ;
if ( ! edev )
goto end ;
if ( ! event & & dp - > debug - > sim_mode ) {
dp_display_disconnect_sync ( dp ) ;
dp - > debug - > abort ( dp - > debug ) ;
}
end :
return NOTIFY_DONE ;
}
static int dp_display_get_usb_extcon ( struct dp_display_private * dp )
{
struct extcon_dev * edev ;
int rc ;
edev = extcon_get_edev_by_phandle ( & dp - > pdev - > dev , 0 ) ;
if ( IS_ERR ( edev ) )
return PTR_ERR ( edev ) ;
dp - > usb_nb . notifier_call = dp_display_usb_notifier ;
dp - > usb_nb . priority = 2 ;
rc = extcon_register_notifier ( edev , EXTCON_USB , & dp - > usb_nb ) ;
if ( rc )
pr_err ( " failed to register for usb event: %d \n " , rc ) ;
return rc ;
}
static void dp_display_deinit_sub_modules ( struct dp_display_private * dp )
{
dp_audio_put ( dp - > panel - > audio ) ;
@ -1195,6 +1225,8 @@ static int dp_init_sub_modules(struct dp_display_private *dp)
dp - > debug - > hdcp_disabled = hdcp_disabled ;
dp_display_update_hdcp_status ( dp , true ) ;
dp_display_get_usb_extcon ( dp ) ;
return rc ;
error_debug :
dp_hpd_put ( dp - > hpd ) ;