提交 1ac91ac5 编写于 作者: C Chunfeng Yun 提交者: Greg Kroah-Hartman

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: NChunfeng Yun <chunfeng.yun@mediatek.com>
Link: https://lore.kernel.org/r/1567070558-29417-12-git-send-email-chunfeng.yun@mediatek.comSigned-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
上级 4602f3bf
...@@ -44,6 +44,7 @@ config USB_MTU3_DUAL_ROLE ...@@ -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.
......
...@@ -199,6 +199,9 @@ struct mtu3_gpd_ring { ...@@ -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 { ...@@ -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;
}; };
......
...@@ -453,9 +453,9 @@ static ssize_t ssusb_mode_write(struct file *file, const char __user *ubuf, ...@@ -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;
......
...@@ -7,6 +7,8 @@ ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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);
} }
...@@ -71,7 +71,7 @@ static inline void ssusb_gadget_exit(struct ssusb_mtk *ssusb) ...@@ -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) ...@@ -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)
{ {
......
...@@ -299,8 +299,9 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) ...@@ -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");
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册