aboutsummaryrefslogtreecommitdiffstats
path: root/target/linux/mediatek/patches-4.14/0188-usb-mtu3-supports-remote-wakeup-for-mt2712-with-two-.patch
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/mediatek/patches-4.14/0188-usb-mtu3-supports-remote-wakeup-for-mt2712-with-two-.patch')
-rw-r--r--target/linux/mediatek/patches-4.14/0188-usb-mtu3-supports-remote-wakeup-for-mt2712-with-two-.patch245
1 files changed, 245 insertions, 0 deletions
diff --git a/target/linux/mediatek/patches-4.14/0188-usb-mtu3-supports-remote-wakeup-for-mt2712-with-two-.patch b/target/linux/mediatek/patches-4.14/0188-usb-mtu3-supports-remote-wakeup-for-mt2712-with-two-.patch
new file mode 100644
index 0000000000..105d6f156b
--- /dev/null
+++ b/target/linux/mediatek/patches-4.14/0188-usb-mtu3-supports-remote-wakeup-for-mt2712-with-two-.patch
@@ -0,0 +1,245 @@
+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(-)
+
+diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
+index d80e4e813248..ed3aec46eda1 100644
+--- 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;
+ };
+
+ /**
+diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h
+index 0f0cbac00192..1fa62ce136b6 100644
+--- a/drivers/usb/mtu3/mtu3_dr.h
++++ b/drivers/usb/mtu3/mtu3_dr.h
+@@ -27,8 +27,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
+
+diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
+index ec76b86dd887..1a1b6cf432a1 100644
+--- 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;
+-
+- 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)
+@@ -244,17 +255,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);
+-}
+diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
+index a2523ead46cf..4cafd4ca8457 100644
+--- a/drivers/usb/mtu3/mtu3_plat.c
++++ b/drivers/usb/mtu3/mtu3_plat.c
+@@ -291,8 +291,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",
+@@ -466,7 +468,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;
+ }
+@@ -482,7 +484,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;
+--
+2.11.0
+