]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
usb: mtu3: supports remote wakeup for mt2712 with two SSUSB IPs
authorChunfeng Yun <chunfeng.yun@mediatek.com>
Wed, 3 Jan 2018 08:53:18 +0000 (16:53 +0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 9 Jan 2018 15:21:27 +0000 (16:21 +0100)
The old way of usb wakeup only supports platform with single SSUSB IP,
such as mt8173, but mt2712 has two SSUSB IPs, so rebuild its flow and
also supports the new glue layer of usb wakeup on mt2712 which is
different from mt8173.

Signed-off-by: Chunfeng Yun <chunfeng.yun@mediatek.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/mtu3/mtu3.h
drivers/usb/mtu3/mtu3_dr.h
drivers/usb/mtu3/mtu3_host.c
drivers/usb/mtu3/mtu3_plat.c

index 3c888d942a9fc23bef618a1119a9d7b15ac66687..2cd00a24afd975ab610d046ba2fc4785b63e6d36 100644 (file)
@@ -229,7 +229,10 @@ struct otg_switch_mtk {
  * @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
- * @wakeup_en: it's true when supports remote wakeup in host mode
+ * @uwk_en: it's true when supports remote wakeup in host mode
+ * @uwk: syscon including usb wakeup glue layer between SSUSB IP and SPM
+ * @uwk_reg_base: the base address of the wakeup glue layer in @uwk
+ * @uwk_vers: the version of the wakeup glue layer
  */
 struct ssusb_mtk {
        struct device *dev;
@@ -253,8 +256,10 @@ struct ssusb_mtk {
        int u3p_dis_msk;
        struct dentry *dbgfs_root;
        /* usb wakeup for host mode */
-       bool wakeup_en;
-       struct regmap *pericfg;
+       bool uwk_en;
+       struct regmap *uwk;
+       u32 uwk_reg_base;
+       u32 uwk_vers;
 };
 
 /**
index c179192408ba12d45d699d5097d690ea2498298d..ae1598d76e02c6939275816e3819f1e2813343fb 100644 (file)
@@ -18,8 +18,7 @@ int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
                                struct device_node *dn);
 int ssusb_host_enable(struct ssusb_mtk *ssusb);
 int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend);
-int ssusb_wakeup_enable(struct ssusb_mtk *ssusb);
-void ssusb_wakeup_disable(struct ssusb_mtk *ssusb);
+void ssusb_wakeup_set(struct ssusb_mtk *ssusb, bool enable);
 
 #else
 
index d237d7e65c443903a7717c3a93f8d5f0e986394c..259beefe3b3b4fd4fc2cd2a61bce96f86ee1bbe0 100644 (file)
 #include "mtu3.h"
 #include "mtu3_dr.h"
 
-#define PERI_WK_CTRL1          0x404
-#define UWK_CTL1_IS_C(x)       (((x) & 0xf) << 26)
-#define UWK_CTL1_IS_E          BIT(25)
-#define UWK_CTL1_IDDIG_C(x)    (((x) & 0xf) << 11)  /* cycle debounce */
-#define UWK_CTL1_IDDIG_E       BIT(10) /* enable debounce */
-#define UWK_CTL1_IDDIG_P       BIT(9)  /* polarity */
-#define UWK_CTL1_IS_P          BIT(6)  /* polarity for ip sleep */
+/* mt8173 etc */
+#define PERI_WK_CTRL1  0x4
+#define WC1_IS_C(x)    (((x) & 0xf) << 26)  /* cycle debounce */
+#define WC1_IS_EN      BIT(25)
+#define WC1_IS_P       BIT(6)  /* polarity for ip sleep */
+
+/* mt2712 etc */
+#define PERI_SSUSB_SPM_CTRL    0x0
+#define SSC_IP_SLEEP_EN        BIT(4)
+#define SSC_SPM_INT_EN         BIT(1)
+
+enum ssusb_uwk_vers {
+       SSUSB_UWK_V1 = 1,
+       SSUSB_UWK_V2,
+};
 
 /*
  * ip-sleep wakeup mode:
  * all clocks can be turn off, but power domain should be kept on
  */
-static void ssusb_wakeup_ip_sleep_en(struct ssusb_mtk *ssusb)
+static void ssusb_wakeup_ip_sleep_set(struct ssusb_mtk *ssusb, bool enable)
 {
-       u32 tmp;
-       struct regmap *pericfg = ssusb->pericfg;
-
-       regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
-       tmp &= ~UWK_CTL1_IS_P;
-       tmp &= ~(UWK_CTL1_IS_C(0xf));
-       tmp |= UWK_CTL1_IS_C(0x8);
-       regmap_write(pericfg, PERI_WK_CTRL1, tmp);
-       regmap_write(pericfg, PERI_WK_CTRL1, tmp | UWK_CTL1_IS_E);
-
-       regmap_read(pericfg, PERI_WK_CTRL1, &tmp);
-       dev_dbg(ssusb->dev, "%s(): WK_CTRL1[P6,E25,C26:29]=%#x\n",
-               __func__, tmp);
-}
-
-static void ssusb_wakeup_ip_sleep_dis(struct ssusb_mtk *ssusb)
-{
-       u32 tmp;
-
-       regmap_read(ssusb->pericfg, PERI_WK_CTRL1, &tmp);
-       tmp &= ~UWK_CTL1_IS_E;
-       regmap_write(ssusb->pericfg, PERI_WK_CTRL1, tmp);
+       u32 reg, msk, val;
+
+       switch (ssusb->uwk_vers) {
+       case SSUSB_UWK_V1:
+               reg = ssusb->uwk_reg_base + PERI_WK_CTRL1;
+               msk = WC1_IS_EN | WC1_IS_C(0xf) | WC1_IS_P;
+               val = enable ? (WC1_IS_EN | WC1_IS_C(0x8)) : 0;
+               break;
+       case SSUSB_UWK_V2:
+               reg = ssusb->uwk_reg_base + PERI_SSUSB_SPM_CTRL;
+               msk = SSC_IP_SLEEP_EN | SSC_SPM_INT_EN;
+               val = enable ? msk : 0;
+               break;
+       default:
+               return;
+       };
+       regmap_update_bits(ssusb->uwk, reg, msk, val);
 }
 
 int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb,
                                struct device_node *dn)
 {
-       struct device *dev = ssusb->dev;
+       struct of_phandle_args args;
+       int ret;
 
-       /*
-        * Wakeup function is optional, so it is not an error if this property
-        * does not exist, and in such case, no need to get relative
-        * properties anymore.
-        */
-       ssusb->wakeup_en = of_property_read_bool(dn, "mediatek,enable-wakeup");
-       if (!ssusb->wakeup_en)
+       /* wakeup function is optional */
+       ssusb->uwk_en = of_property_read_bool(dn, "wakeup-source");
+       if (!ssusb->uwk_en)
                return 0;
 
-       ssusb->pericfg = syscon_regmap_lookup_by_phandle(dn,
-                                               "mediatek,syscon-wakeup");
-       if (IS_ERR(ssusb->pericfg)) {
-               dev_err(dev, "fail to get pericfg regs\n");
-               return PTR_ERR(ssusb->pericfg);
-       }
+       ret = of_parse_phandle_with_fixed_args(dn,
+                               "mediatek,syscon-wakeup", 2, 0, &args);
+       if (ret)
+               return ret;
 
-       return 0;
+       ssusb->uwk_reg_base = args.args[0];
+       ssusb->uwk_vers = args.args[1];
+       ssusb->uwk = syscon_node_to_regmap(args.np);
+       of_node_put(args.np);
+       dev_info(ssusb->dev, "uwk - reg:0x%x, version:%d\n",
+                       ssusb->uwk_reg_base, ssusb->uwk_vers);
+
+       return PTR_ERR_OR_ZERO(ssusb->uwk);
+}
+
+void ssusb_wakeup_set(struct ssusb_mtk *ssusb, bool enable)
+{
+       if (ssusb->uwk_en)
+               ssusb_wakeup_ip_sleep_set(ssusb, enable);
 }
 
 static void host_ports_num_get(struct ssusb_mtk *ssusb)
@@ -235,17 +246,3 @@ void ssusb_host_exit(struct ssusb_mtk *ssusb)
        of_platform_depopulate(ssusb->dev);
        ssusb_host_cleanup(ssusb);
 }
-
-int ssusb_wakeup_enable(struct ssusb_mtk *ssusb)
-{
-       if (ssusb->wakeup_en)
-               ssusb_wakeup_ip_sleep_en(ssusb);
-
-       return 0;
-}
-
-void ssusb_wakeup_disable(struct ssusb_mtk *ssusb)
-{
-       if (ssusb->wakeup_en)
-               ssusb_wakeup_ip_sleep_dis(ssusb);
-}
index 5b2110bdee96d96d8cf8b7726cf9577d73edb0a9..628d5ce356ca0d8f9f940af4eab2d13f20f2c84d 100644 (file)
@@ -282,8 +282,10 @@ static int get_ssusb_rscs(struct platform_device *pdev, struct ssusb_mtk *ssusb)
 
        /* if host role is supported */
        ret = ssusb_wakeup_of_property_parse(ssusb, node);
-       if (ret)
+       if (ret) {
+               dev_err(dev, "failed to parse uwk property\n");
                return ret;
+       }
 
        /* optional property, ignore the error if it does not exist */
        of_property_read_u32(node, "mediatek,u3p-dis-msk",
@@ -457,7 +459,7 @@ static int __maybe_unused mtu3_suspend(struct device *dev)
        ssusb_host_disable(ssusb, true);
        ssusb_phy_power_off(ssusb);
        ssusb_clks_disable(ssusb);
-       ssusb_wakeup_enable(ssusb);
+       ssusb_wakeup_set(ssusb, true);
 
        return 0;
 }
@@ -473,7 +475,7 @@ static int __maybe_unused mtu3_resume(struct device *dev)
        if (!ssusb->is_host)
                return 0;
 
-       ssusb_wakeup_disable(ssusb);
+       ssusb_wakeup_set(ssusb, false);
        ret = ssusb_clks_enable(ssusb);
        if (ret)
                goto clks_err;