1 /* 2 * mtu3_dr.c - dual role switch and host glue layer 3 * 4 * Copyright (C) 2016 MediaTek Inc. 5 * 6 * Author: Chunfeng Yun <chunfeng.yun@mediatek.com> 7 * 8 * This software is licensed under the terms of the GNU General Public 9 * License version 2, as published by the Free Software Foundation, and 10 * may be copied, distributed, and modified under those terms. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 */ 18 19 #include <linux/clk.h> 20 #include <linux/iopoll.h> 21 #include <linux/irq.h> 22 #include <linux/kernel.h> 23 #include <linux/mfd/syscon.h> 24 #include <linux/of_device.h> 25 #include <linux/regmap.h> 26 27 #include "mtu3.h" 28 #include "mtu3_dr.h" 29 30 #define PERI_WK_CTRL1 0x404 31 #define UWK_CTL1_IS_C(x) (((x) & 0xf) << 26) 32 #define UWK_CTL1_IS_E BIT(25) 33 #define UWK_CTL1_IDDIG_C(x) (((x) & 0xf) << 11) /* cycle debounce */ 34 #define UWK_CTL1_IDDIG_E BIT(10) /* enable debounce */ 35 #define UWK_CTL1_IDDIG_P BIT(9) /* polarity */ 36 #define UWK_CTL1_IS_P BIT(6) /* polarity for ip sleep */ 37 38 /* 39 * ip-sleep wakeup mode: 40 * all clocks can be turn off, but power domain should be kept on 41 */ 42 static void ssusb_wakeup_ip_sleep_en(struct ssusb_mtk *ssusb) 43 { 44 u32 tmp; 45 struct regmap *pericfg = ssusb->pericfg; 46 47 regmap_read(pericfg, PERI_WK_CTRL1, &tmp); 48 tmp &= ~UWK_CTL1_IS_P; 49 tmp &= ~(UWK_CTL1_IS_C(0xf)); 50 tmp |= UWK_CTL1_IS_C(0x8); 51 regmap_write(pericfg, PERI_WK_CTRL1, tmp); 52 regmap_write(pericfg, PERI_WK_CTRL1, tmp | UWK_CTL1_IS_E); 53 54 regmap_read(pericfg, PERI_WK_CTRL1, &tmp); 55 dev_dbg(ssusb->dev, "%s(): WK_CTRL1[P6,E25,C26:29]=%#x\n", 56 __func__, tmp); 57 } 58 59 static void ssusb_wakeup_ip_sleep_dis(struct ssusb_mtk *ssusb) 60 { 61 u32 tmp; 62 63 regmap_read(ssusb->pericfg, PERI_WK_CTRL1, &tmp); 64 tmp &= ~UWK_CTL1_IS_E; 65 regmap_write(ssusb->pericfg, PERI_WK_CTRL1, tmp); 66 } 67 68 int ssusb_wakeup_of_property_parse(struct ssusb_mtk *ssusb, 69 struct device_node *dn) 70 { 71 struct device *dev = ssusb->dev; 72 73 /* 74 * Wakeup function is optional, so it is not an error if this property 75 * does not exist, and in such case, no need to get relative 76 * properties anymore. 77 */ 78 ssusb->wakeup_en = of_property_read_bool(dn, "mediatek,enable-wakeup"); 79 if (!ssusb->wakeup_en) 80 return 0; 81 82 ssusb->wk_deb_p0 = devm_clk_get(dev, "wakeup_deb_p0"); 83 if (IS_ERR(ssusb->wk_deb_p0)) { 84 dev_err(dev, "fail to get wakeup_deb_p0\n"); 85 return PTR_ERR(ssusb->wk_deb_p0); 86 } 87 88 if (of_property_read_bool(dn, "wakeup_deb_p1")) { 89 ssusb->wk_deb_p1 = devm_clk_get(dev, "wakeup_deb_p1"); 90 if (IS_ERR(ssusb->wk_deb_p1)) { 91 dev_err(dev, "fail to get wakeup_deb_p1\n"); 92 return PTR_ERR(ssusb->wk_deb_p1); 93 } 94 } 95 96 ssusb->pericfg = syscon_regmap_lookup_by_phandle(dn, 97 "mediatek,syscon-wakeup"); 98 if (IS_ERR(ssusb->pericfg)) { 99 dev_err(dev, "fail to get pericfg regs\n"); 100 return PTR_ERR(ssusb->pericfg); 101 } 102 103 return 0; 104 } 105 106 static int ssusb_wakeup_clks_enable(struct ssusb_mtk *ssusb) 107 { 108 int ret; 109 110 ret = clk_prepare_enable(ssusb->wk_deb_p0); 111 if (ret) { 112 dev_err(ssusb->dev, "failed to enable wk_deb_p0\n"); 113 goto usb_p0_err; 114 } 115 116 ret = clk_prepare_enable(ssusb->wk_deb_p1); 117 if (ret) { 118 dev_err(ssusb->dev, "failed to enable wk_deb_p1\n"); 119 goto usb_p1_err; 120 } 121 122 return 0; 123 124 usb_p1_err: 125 clk_disable_unprepare(ssusb->wk_deb_p0); 126 usb_p0_err: 127 return -EINVAL; 128 } 129 130 static void ssusb_wakeup_clks_disable(struct ssusb_mtk *ssusb) 131 { 132 clk_disable_unprepare(ssusb->wk_deb_p1); 133 clk_disable_unprepare(ssusb->wk_deb_p0); 134 } 135 136 static void host_ports_num_get(struct ssusb_mtk *ssusb) 137 { 138 u32 xhci_cap; 139 140 xhci_cap = mtu3_readl(ssusb->ippc_base, U3D_SSUSB_IP_XHCI_CAP); 141 ssusb->u2_ports = SSUSB_IP_XHCI_U2_PORT_NUM(xhci_cap); 142 ssusb->u3_ports = SSUSB_IP_XHCI_U3_PORT_NUM(xhci_cap); 143 144 dev_dbg(ssusb->dev, "host - u2_ports:%d, u3_ports:%d\n", 145 ssusb->u2_ports, ssusb->u3_ports); 146 } 147 148 /* only configure ports will be used later */ 149 int ssusb_host_enable(struct ssusb_mtk *ssusb) 150 { 151 void __iomem *ibase = ssusb->ippc_base; 152 int num_u3p = ssusb->u3_ports; 153 int num_u2p = ssusb->u2_ports; 154 u32 check_clk; 155 u32 value; 156 int i; 157 158 /* power on host ip */ 159 mtu3_clrbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN); 160 161 /* power on and enable all u3 ports */ 162 for (i = 0; i < num_u3p; i++) { 163 value = mtu3_readl(ibase, SSUSB_U3_CTRL(i)); 164 value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS); 165 value |= SSUSB_U3_PORT_HOST_SEL; 166 mtu3_writel(ibase, SSUSB_U3_CTRL(i), value); 167 } 168 169 /* power on and enable all u2 ports */ 170 for (i = 0; i < num_u2p; i++) { 171 value = mtu3_readl(ibase, SSUSB_U2_CTRL(i)); 172 value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS); 173 value |= SSUSB_U2_PORT_HOST_SEL; 174 mtu3_writel(ibase, SSUSB_U2_CTRL(i), value); 175 } 176 177 check_clk = SSUSB_XHCI_RST_B_STS; 178 if (num_u3p) 179 check_clk = SSUSB_U3_MAC_RST_B_STS; 180 181 return ssusb_check_clocks(ssusb, check_clk); 182 } 183 184 int ssusb_host_disable(struct ssusb_mtk *ssusb, bool suspend) 185 { 186 void __iomem *ibase = ssusb->ippc_base; 187 int num_u3p = ssusb->u3_ports; 188 int num_u2p = ssusb->u2_ports; 189 u32 value; 190 int ret; 191 int i; 192 193 /* power down and disable all u3 ports */ 194 for (i = 0; i < num_u3p; i++) { 195 value = mtu3_readl(ibase, SSUSB_U3_CTRL(i)); 196 value |= SSUSB_U3_PORT_PDN; 197 value |= suspend ? 0 : SSUSB_U3_PORT_DIS; 198 mtu3_writel(ibase, SSUSB_U3_CTRL(i), value); 199 } 200 201 /* power down and disable all u2 ports */ 202 for (i = 0; i < num_u2p; i++) { 203 value = mtu3_readl(ibase, SSUSB_U2_CTRL(i)); 204 value |= SSUSB_U2_PORT_PDN; 205 value |= suspend ? 0 : SSUSB_U2_PORT_DIS; 206 mtu3_writel(ibase, SSUSB_U2_CTRL(i), value); 207 } 208 209 /* power down host ip */ 210 mtu3_setbits(ibase, U3D_SSUSB_IP_PW_CTRL1, SSUSB_IP_HOST_PDN); 211 212 if (!suspend) 213 return 0; 214 215 /* wait for host ip to sleep */ 216 ret = readl_poll_timeout(ibase + U3D_SSUSB_IP_PW_STS1, value, 217 (value & SSUSB_IP_SLEEP_STS), 100, 100000); 218 if (ret) 219 dev_err(ssusb->dev, "ip sleep failed!!!\n"); 220 221 return ret; 222 } 223 224 static void ssusb_host_setup(struct ssusb_mtk *ssusb) 225 { 226 host_ports_num_get(ssusb); 227 228 /* 229 * power on host and power on/enable all ports 230 * if support OTG, gadget driver will switch port0 to device mode 231 */ 232 ssusb_host_enable(ssusb); 233 234 /* if port0 supports dual-role, works as host mode by default */ 235 ssusb_set_vbus(&ssusb->otg_switch, 1); 236 } 237 238 static void ssusb_host_cleanup(struct ssusb_mtk *ssusb) 239 { 240 if (ssusb->is_host) 241 ssusb_set_vbus(&ssusb->otg_switch, 0); 242 243 ssusb_host_disable(ssusb, false); 244 } 245 246 /* 247 * If host supports multiple ports, the VBUSes(5V) of ports except port0 248 * which supports OTG are better to be enabled by default in DTS. 249 * Because the host driver will keep link with devices attached when system 250 * enters suspend mode, so no need to control VBUSes after initialization. 251 */ 252 int ssusb_host_init(struct ssusb_mtk *ssusb, struct device_node *parent_dn) 253 { 254 struct device *parent_dev = ssusb->dev; 255 int ret; 256 257 ssusb_host_setup(ssusb); 258 259 ret = of_platform_populate(parent_dn, NULL, NULL, parent_dev); 260 if (ret) { 261 dev_dbg(parent_dev, "failed to create child devices at %pOF\n", 262 parent_dn); 263 return ret; 264 } 265 266 dev_info(parent_dev, "xHCI platform device register success...\n"); 267 268 return 0; 269 } 270 271 void ssusb_host_exit(struct ssusb_mtk *ssusb) 272 { 273 of_platform_depopulate(ssusb->dev); 274 ssusb_host_cleanup(ssusb); 275 } 276 277 int ssusb_wakeup_enable(struct ssusb_mtk *ssusb) 278 { 279 int ret = 0; 280 281 if (ssusb->wakeup_en) { 282 ret = ssusb_wakeup_clks_enable(ssusb); 283 ssusb_wakeup_ip_sleep_en(ssusb); 284 } 285 return ret; 286 } 287 288 void ssusb_wakeup_disable(struct ssusb_mtk *ssusb) 289 { 290 if (ssusb->wakeup_en) { 291 ssusb_wakeup_ip_sleep_dis(ssusb); 292 ssusb_wakeup_clks_disable(ssusb); 293 } 294 } 295