diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/mtu3/mtu3.h | 11 | ||||
-rw-r--r-- | drivers/usb/mtu3/mtu3_dr.h | 3 | ||||
-rw-r--r-- | drivers/usb/mtu3/mtu3_host.c | 115 | ||||
-rw-r--r-- | 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 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; |