usb: mtu3: support option to disable usb2 ports
authorChunfeng Yun <chunfeng.yun@mediatek.com>
Thu, 15 Jul 2021 09:07:53 +0000 (17:07 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 27 Jul 2021 13:58:37 +0000 (15:58 +0200)
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@mediatek.com>
Link: https://lore.kernel.org/r/1626340078-29111-9-git-send-email-chunfeng.yun@mediatek.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/mtu3/mtu3.h
drivers/usb/mtu3/mtu3_host.c
drivers/usb/mtu3/mtu3_plat.c

index bc82c7f..0ae9b33 100644 (file)
@@ -228,6 +228,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
@@ -252,6 +255,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 */
index 93a1a4c..6185bac 100644 (file)
@@ -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;
index c0615f6..5162b99 100644 (file)
@@ -225,6 +225,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)) {
@@ -241,6 +243,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;
 
@@ -253,9 +258,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;
 }