diff options
Diffstat (limited to 'drivers/usb/mtu3/mtu3_dr.c')
| -rw-r--r-- | drivers/usb/mtu3/mtu3_dr.c | 48 | 
1 files changed, 47 insertions, 1 deletions
diff --git a/drivers/usb/mtu3/mtu3_dr.c b/drivers/usb/mtu3/mtu3_dr.c index 5fcb71af875a..08e18448e8b8 100644 --- a/drivers/usb/mtu3/mtu3_dr.c +++ b/drivers/usb/mtu3/mtu3_dr.c @@ -7,6 +7,8 @@   * Author: Chunfeng Yun <[email protected]>   */ +#include <linux/usb/role.h> +  #include "mtu3.h"  #include "mtu3_dr.h"  #include "mtu3_debug.h" @@ -280,7 +282,7 @@ static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx)   * This is useful in special cases, such as uses TYPE-A receptacle but also   * wants to support dual-role mode.   */ -void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host) +void ssusb_mode_switch(struct ssusb_mtk *ssusb, int to_host)  {  	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; @@ -318,6 +320,47 @@ void ssusb_set_force_mode(struct ssusb_mtk *ssusb,  	mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value);  } +static int ssusb_role_sw_set(struct device *dev, enum usb_role role) +{ +	struct ssusb_mtk *ssusb = dev_get_drvdata(dev); +	bool to_host = false; + +	if (role == USB_ROLE_HOST) +		to_host = true; + +	if (to_host ^ ssusb->is_host) +		ssusb_mode_switch(ssusb, to_host); + +	return 0; +} + +static enum usb_role ssusb_role_sw_get(struct device *dev) +{ +	struct ssusb_mtk *ssusb = dev_get_drvdata(dev); +	enum usb_role role; + +	role = ssusb->is_host ? USB_ROLE_HOST : USB_ROLE_DEVICE; + +	return role; +} + +static int ssusb_role_sw_register(struct otg_switch_mtk *otg_sx) +{ +	struct usb_role_switch_desc role_sx_desc = { 0 }; +	struct ssusb_mtk *ssusb = +		container_of(otg_sx, struct ssusb_mtk, otg_switch); + +	if (!otg_sx->role_sw_used) +		return 0; + +	role_sx_desc.set = ssusb_role_sw_set; +	role_sx_desc.get = ssusb_role_sw_get; +	role_sx_desc.fwnode = dev_fwnode(ssusb->dev); +	otg_sx->role_sw = usb_role_switch_register(ssusb->dev, &role_sx_desc); + +	return PTR_ERR_OR_ZERO(otg_sx->role_sw); +} +  int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)  {  	struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; @@ -328,6 +371,8 @@ int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)  	if (otg_sx->manual_drd_enabled)  		ssusb_dr_debugfs_init(ssusb); +	else if (otg_sx->role_sw_used) +		ret = ssusb_role_sw_register(otg_sx);  	else  		ret = ssusb_extcon_register(otg_sx); @@ -340,4 +385,5 @@ void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)  	cancel_work_sync(&otg_sx->id_work);  	cancel_work_sync(&otg_sx->vbus_work); +	usb_role_switch_unregister(otg_sx->role_sw);  }  |