summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/usb/mtu3/mtu3.h11
-rw-r--r--drivers/usb/mtu3/mtu3_dr.h3
-rw-r--r--drivers/usb/mtu3/mtu3_host.c115
-rw-r--r--drivers/usb/mtu3/mtu3_plat.c8
4 files changed, 70 insertions, 67 deletions
diff --git a/drivers/usb/mtu3/mtu3.h b/drivers/usb/mtu3/mtu3.h
index 3c888d942a9f..2cd00a24afd9 100644
--- a/drivers/usb/mtu3/mtu3.h
+++ b/drivers/usb/mtu3/mtu3.h
@@ -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;
};
/**
diff --git a/drivers/usb/mtu3/mtu3_dr.h b/drivers/usb/mtu3/mtu3_dr.h
index c179192408ba..ae1598d76e02 100644
--- a/drivers/usb/mtu3/mtu3_dr.h
+++ b/drivers/usb/mtu3/mtu3_dr.h
@@ -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
diff --git a/drivers/usb/mtu3/mtu3_host.c b/drivers/usb/mtu3/mtu3_host.c
index d237d7e65c44..259beefe3b3b 100644
--- a/drivers/usb/mtu3/mtu3_host.c
+++ b/drivers/usb/mtu3/mtu3_host.c
@@ -18,66 +18,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)
@@ -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);
-}
diff --git a/drivers/usb/mtu3/mtu3_plat.c b/drivers/usb/mtu3/mtu3_plat.c
index 5b2110bdee96..628d5ce356ca 100644
--- a/drivers/usb/mtu3/mtu3_plat.c
+++ b/drivers/usb/mtu3/mtu3_plat.c
@@ -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;
OpenPOWER on IntegriCloud