Add support to disable specific usb2 host ports, it's useful when a usb2 port is disabled on some platforms, but enabled on others for the same SoC. Signed-off-by: Chunfeng Yun <chunfeng.yun@xxxxxxxxxxxx> --- drivers/usb/mtu3/mtu3.h | 4 ++++ drivers/usb/mtu3/mtu3_host.c | 8 +++++++- drivers/usb/mtu3/mtu3_plat.c | 11 +++++++++-- 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h index b56284d28c71..710abe83ba1a 100644 --- a/drivers/usb/mtu3/mtu3.h +++ b/drivers/usb/mtu3/mtu3.h @@ -229,6 +229,9 @@ struct otg_switch_mtk { * host only, device only or dual-role mode * @u2_ports: number of usb2.0 host ports * @u3_ports: number of usb3.0 host ports + * @u2p_dis_msk: mask of disabling usb2 ports, e.g. bit0==1 to + * disable u2port0, bit1==1 to disable u2port1,... etc, + * but when use dual-role mode, can't disable u2port0 * @u3p_dis_msk: mask of disabling usb3 ports, for example, bit0==1 to * disable u3port0, bit1==1 to disable u3port1,... etc * @dbgfs_root: only used when supports manual dual-role switch via debugfs @@ -256,6 +259,7 @@ struct ssusb_mtk { bool is_host; int u2_ports; int u3_ports; + int u2p_dis_msk; int u3p_dis_msk; struct dentry *dbgfs_root; /* usb wakeup for host mode */ diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c index 93a1a4c11e1e..6185bac5fecf 100644 --- a/drivers/usb/mtu3/mtu3_host.c +++ b/drivers/usb/mtu3/mtu3_host.c @@ -155,6 +155,9 @@ int ssusb_host_enable(struct ssusb_mtk *ssusb) /* power on and enable all u2 ports */ for (i = 0; i < num_u2p; i++) { + if ((0x1 << i) & ssusb->u2p_dis_msk) + continue; + value = mtu3_readl(ibase, SSUSB_U2_CTRL(i)); value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS); value |= SSUSB_U2_PORT_HOST_SEL; @@ -188,8 +191,11 @@ int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend) mtu3_writel(ibase, SSUSB_U3_CTRL(i), value); } - /* power down and disable all u2 ports */ + /* power down and disable u2 ports except skipped ones */ for (i = 0; i < num_u2p; i++) { + if ((0x1 << i) & ssusb->u2p_dis_msk) + continue; + value = mtu3_readl(ibase, SSUSB_U2_CTRL(i)); value |= SSUSB_U2_PORT_PDN; value |= suspend ? 0 : SSUSB_U2_PORT_DIS; diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c index bbfabdc1e79b..93e52e6b6811 100644 --- a/drivers/usb/mtu3/mtu3_plat.c +++ b/drivers/usb/mtu3/mtu3_plat.c @@ -283,6 +283,8 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) /* optional property, ignore the error if it does not exist */ of_property_read_u32(node, "mediatek,u3p-dis-msk", &ssusb->u3p_dis_msk); + of_property_read_u32(node, "mediatek,u2p-dis-msk", + &ssusb->u2p_dis_msk); otg_sx->vbus = devm_regulator_get(dev, "vbus"); if (IS_ERR(otg_sx->vbus)) { @@ -299,6 +301,9 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) of_property_read_bool(node, "enable-manual-drd"); otg_sx->role_sw_used = of_property_read_bool(node, "usb-role-switch"); + /* can't disable port0 when use dual-role mode */ + ssusb->u2p_dis_msk &= ~0x1; + if (otg_sx->role_sw_used || otg_sx->manual_drd_enabled) goto out; @@ -311,9 +316,11 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb) } out: - dev_info(dev, "dr_mode: %d, is_u3_dr: %d, u3p_dis_msk: %x, drd: %s\n", - ssusb->dr_mode, otg_sx->is_u3_drd, ssusb->u3p_dis_msk, + dev_info(dev, "dr_mode: %d, is_u3_dr: %d, drd: %s\n", + ssusb->dr_mode, otg_sx->is_u3_drd, otg_sx->manual_drd_enabled ? "manual" : "auto"); + dev_info(dev, "u2p_dis_msk: %x, u3p_dis_msk: %x\n", + ssusb->u2p_dis_msk, ssusb->u3p_dis_msk); return 0; } -- 2.18.0