1
0
Fork 0

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>
alistair/sunxi64-5.4-dsi
Chunfeng Yun 2019-08-29 17:22:38 +08:00 committed by Greg Kroah-Hartman
parent 4602f3bff2
commit 1ac91ac5d0
6 changed files with 60 additions and 7 deletions

View File

@ -44,6 +44,7 @@ config USB_MTU3_DUAL_ROLE
bool "Dual Role mode" bool "Dual Role mode"
depends on ((USB=y || USB=USB_MTU3) && (USB_GADGET=y || USB_GADGET=USB_MTU3)) depends on ((USB=y || USB=USB_MTU3) && (USB_GADGET=y || USB_GADGET=USB_MTU3))
depends on (EXTCON=y || EXTCON=USB_MTU3) depends on (EXTCON=y || EXTCON=USB_MTU3)
select USB_ROLE_SWITCH
help help
This is the default mode of working of MTU3 controller where This is the default mode of working of MTU3 controller where
both host and gadget features are enabled. both host and gadget features are enabled.

View File

@ -199,6 +199,9 @@ struct mtu3_gpd_ring {
* @id_nb : notifier for iddig(idpin) detection * @id_nb : notifier for iddig(idpin) detection
* @id_work : work of iddig detection notifier * @id_work : work of iddig detection notifier
* @id_event : event of iddig detecion 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 * @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 * @manual_drd_enabled: it's true when supports dual-role device by debugfs
* to switch host/device modes depending on user input. * to switch host/device modes depending on user input.
@ -212,6 +215,8 @@ struct otg_switch_mtk {
struct notifier_block id_nb; struct notifier_block id_nb;
struct work_struct id_work; struct work_struct id_work;
unsigned long id_event; unsigned long id_event;
struct usb_role_switch *role_sw;
bool role_sw_used;
bool is_u3_drd; bool is_u3_drd;
bool manual_drd_enabled; bool manual_drd_enabled;
}; };

View File

@ -453,9 +453,9 @@ static ssize_t ssusb_mode_write(struct file *file, const char __user *ubuf,
return -EFAULT; return -EFAULT;
if (!strncmp(buf, "host", 4) && !ssusb->is_host) { 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) { } else if (!strncmp(buf, "device", 6) && ssusb->is_host) {
ssusb_mode_manual_switch(ssusb, 0); ssusb_mode_switch(ssusb, 0);
} else { } else {
dev_err(ssusb->dev, "wrong or duplicated setting\n"); dev_err(ssusb->dev, "wrong or duplicated setting\n");
return -EINVAL; return -EINVAL;

View File

@ -7,6 +7,8 @@
* Author: Chunfeng Yun <chunfeng.yun@mediatek.com> * Author: Chunfeng Yun <chunfeng.yun@mediatek.com>
*/ */
#include <linux/usb/role.h>
#include "mtu3.h" #include "mtu3.h"
#include "mtu3_dr.h" #include "mtu3_dr.h"
#include "mtu3_debug.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 * This is useful in special cases, such as uses TYPE-A receptacle but also
* wants to support dual-role mode. * 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; 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); 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) int ssusb_otg_switch_init(struct ssusb_mtk *ssusb)
{ {
struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; 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) if (otg_sx->manual_drd_enabled)
ssusb_dr_debugfs_init(ssusb); ssusb_dr_debugfs_init(ssusb);
else if (otg_sx->role_sw_used)
ret = ssusb_role_sw_register(otg_sx);
else else
ret = ssusb_extcon_register(otg_sx); 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->id_work);
cancel_work_sync(&otg_sx->vbus_work); cancel_work_sync(&otg_sx->vbus_work);
usb_role_switch_unregister(otg_sx->role_sw);
} }

View File

@ -71,7 +71,7 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb)
#if IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE) #if IS_ENABLED(CONFIG_USB_MTU3_DUAL_ROLE)
int ssusb_otg_switch_init(struct ssusb_mtk *ssusb); int ssusb_otg_switch_init(struct ssusb_mtk *ssusb);
void ssusb_otg_switch_exit(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); int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on);
void ssusb_set_force_mode(struct ssusb_mtk *ssusb, void ssusb_set_force_mode(struct ssusb_mtk *ssusb,
enum mtu3_dr_force_mode mode); 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_otg_switch_exit(struct ssusb_mtk *ssusb)
{} {}
static inline void static inline void ssusb_mode_switch(struct ssusb_mtk *ssusb, int to_host)
ssusb_mode_manual_switch(struct ssusb_mtk *ssusb, int to_host) {} {}
static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on) static inline int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on)
{ {

View File

@ -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->is_u3_drd = of_property_read_bool(node, "mediatek,usb3-drd");
otg_sx->manual_drd_enabled = otg_sx->manual_drd_enabled =
of_property_read_bool(node, "enable-manual-drd"); 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); otg_sx->edev = extcon_get_edev_by_phandle(ssusb->dev, 0);
if (IS_ERR(otg_sx->edev)) { if (IS_ERR(otg_sx->edev)) {
dev_err(ssusb->dev, "couldn't get extcon device\n"); dev_err(ssusb->dev, "couldn't get extcon device\n");