usb: mtu3: register a USB Role Switch for dual role mode
Because extcon is not allowed for new bindings, and the dual role switch is supported by USB Role Switch, especially for Type-C drivers, so register a USB Role Switch to support the new way Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com> Link: https://lore.kernel.org/r/1567070558-29417-12-git-send-email-chunfeng.yun@mediatek.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
4602f3bff2
commit
1ac91ac5d0
|
@ -44,6 +44,7 @@ config USB_MTU3_DUAL_ROLE
|
|||
bool "Dual Role mode"
|
||||
depends on ((USB=y || USB=USB_MTU3) && (USB_GADGET=y || USB_GADGET=USB_MTU3))
|
||||
depends on (EXTCON=y || EXTCON=USB_MTU3)
|
||||
select USB_ROLE_SWITCH
|
||||
help
|
||||
This is the default mode of working of MTU3 controller where
|
||||
both host and gadget features are enabled.
|
||||
|
|
|
@ -199,6 +199,9 @@ struct mtu3_gpd_ring {
|
|||
* @id_nb : notifier for iddig(idpin) detection
|
||||
* @id_work : work of iddig detection notifier
|
||||
* @id_event : event of iddig detecion notifier
|
||||
* @role_sw : use USB Role Switch to support dual-role switch, can't use
|
||||
* extcon at the same time, and extcon is deprecated.
|
||||
* @role_sw_used : true when the USB Role Switch is used.
|
||||
* @is_u3_drd: whether port0 supports usb3.0 dual-role device or not
|
||||
* @manual_drd_enabled: it's true when supports dual-role device by debugfs
|
||||
* to switch host/device modes depending on user input.
|
||||
|
@ -212,6 +215,8 @@ struct otg_switch_mtk {
|
|||
struct notifier_block id_nb;
|
||||
struct work_struct id_work;
|
||||
unsigned long id_event;
|
||||
struct usb_role_switch *role_sw;
|
||||
bool role_sw_used;
|
||||
bool is_u3_drd;
|
||||
bool manual_drd_enabled;
|
||||
};
|
||||
|
|
|
@ -453,9 +453,9 @@ static ssize_t ssusb_mode_write(struct file *file, const char __user *ubuf,
|
|||
return -EFAULT;
|
||||
|
||||
if (!strncmp(buf, "host", 4) && !ssusb->is_host) {
|
||||
ssusb_mode_manual_switch(ssusb, 1);
|
||||
ssusb_mode_switch(ssusb, 1);
|
||||
} else if (!strncmp(buf, "device", 6) && ssusb->is_host) {
|
||||
ssusb_mode_manual_switch(ssusb, 0);
|
||||
ssusb_mode_switch(ssusb, 0);
|
||||
} else {
|
||||
dev_err(ssusb->dev, "wrong or duplicated setting\n");
|
||||
return -EINVAL;
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
|
||||
*/
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
|
@ -71,7 +71,7 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
|
|||
#if IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE)
|
||||
int ssusb_otg_switch_init(struct ssusb_mtk *ssusb);
|
||||
void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb);
|
||||
void ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host);
|
||||
void ssusb_mode_switch(struct ssusb_mtk *ssusb, int to_host);
|
||||
int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on);
|
||||
void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
|
||||
enum mtu3_dr_force_mode mode);
|
||||
|
@ -86,8 +86,8 @@ static inline int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
|
|||
static inline void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb)
|
||||
{}
|
||||
|
||||
static inline void
|
||||
ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host) {}
|
||||
static inline void ssusb_mode_switch(struct ssusb_mtk *ssusb, int to_host)
|
||||
{}
|
||||
|
||||
static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
|
||||
{
|
||||
|
|
|
@ -299,8 +299,9 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
|
|||
otg_sx->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd");
|
||||
otg_sx->manual_drd_enabled =
|
||||
of_property_read_bool(node, "enable-manual-drd");
|
||||
otg_sx->role_sw_used = of_property_read_bool(node, "usb-role-switch");
|
||||
|
||||
if (of_property_read_bool(node, "extcon")) {
|
||||
if (!otg_sx->role_sw_used && of_property_read_bool(node, "extcon")) {
|
||||
otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0);
|
||||
if (IS_ERR(otg_sx->edev)) {
|
||||
dev_err(ssusb->dev, "couldn't get extcon device\n");
|
||||
|
|
Loading…
Reference in New Issue