234 lines
6.9 KiB
Diff
234 lines
6.9 KiB
Diff
From 354655aaf0f71ce2b567cbc02afb0664c99e434e Mon Sep 17 00:00:00 2001
|
|
From: Chunfeng Yun <chunfeng.yun@mediatek.com>
|
|
Date: Wed, 3 Jan 2018 16:53:18 +0800
|
|
Subject: [PATCH 188/224] usb: mtu3: supports remote wakeup for mt2712 with two
|
|
SSUSB IPs
|
|
|
|
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 | 11 +++--
|
|
drivers/usb/mtu3/mtu3_dr.h | 3 +-
|
|
drivers/usb/mtu3/mtu3_host.c | 115 +++++++++++++++++++++----------------------
|
|
drivers/usb/mtu3/mtu3_plat.c | 8 +--
|
|
4 files changed, 70 insertions(+), 67 deletions(-)
|
|
|
|
--- a/drivers/usb/mtu3/mtu3.h
|
|
+++ b/drivers/usb/mtu3/mtu3.h
|
|
@@ -238,7 +238,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;
|
|
@@ -262,8 +265,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;
|
|
};
|
|
|
|
/**
|
|
--- a/drivers/usb/mtu3/mtu3_dr.h
|
|
+++ b/drivers/usb/mtu3/mtu3_dr.h
|
|
@@ -27,8 +27,7 @@ int ssusb_wakeup_of_property_parse(struc
|
|
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
|
|
|
|
--- a/drivers/usb/mtu3/mtu3_host.c
|
|
+++ b/drivers/usb/mtu3/mtu3_host.c
|
|
@@ -27,66 +27,77 @@
|
|
#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;
|
|
+ u32 reg, msk, val;
|
|
|
|
- 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);
|
|
+ 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)
|
|
@@ -244,17 +255,3 @@ void ssusb_host_exit(struct ssusb_mtk *s
|
|
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);
|
|
-}
|
|
--- a/drivers/usb/mtu3/mtu3_plat.c
|
|
+++ b/drivers/usb/mtu3/mtu3_plat.c
|
|
@@ -291,8 +291,10 @@ static int get_ssusb_rscs(struct platfor
|
|
|
|
/* 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",
|
|
@@ -466,7 +468,7 @@ static int __maybe_unused mtu3_suspend(s
|
|
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;
|
|
}
|
|
@@ -482,7 +484,7 @@ static int __maybe_unused mtu3_resume(st
|
|
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;
|