mtu3_dr.c (8456B)
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * mtu3_dr.c - dual role switch and host glue layer 4 * 5 * Copyright (C) 2016 MediaTek Inc. 6 * 7 * Author: Chunfeng Yun <chunfeng.yun@mediatek.com> 8 */ 9 10#include "mtu3.h" 11#include "mtu3_dr.h" 12#include "mtu3_debug.h" 13 14#define USB2_PORT 2 15#define USB3_PORT 3 16 17static inline struct ssusb_mtk *otg_sx_to_ssusb(struct otg_switch_mtk *otg_sx) 18{ 19 return container_of(otg_sx, struct ssusb_mtk, otg_switch); 20} 21 22static void toggle_opstate(struct ssusb_mtk *ssusb) 23{ 24 mtu3_setbits(ssusb->mac_base, U3D_DEVICE_CONTROL, DC_SESSION); 25 mtu3_setbits(ssusb->mac_base, U3D_POWER_MANAGEMENT, SOFT_CONN); 26} 27 28/* only port0 supports dual-role mode */ 29static int ssusb_port0_switch(struct ssusb_mtk *ssusb, 30 int version, bool tohost) 31{ 32 void __iomem *ibase = ssusb->ippc_base; 33 u32 value; 34 35 dev_dbg(ssusb->dev, "%s (switch u%d port0 to %s)\n", __func__, 36 version, tohost ? "host" : "device"); 37 38 if (version == USB2_PORT) { 39 /* 1. power off and disable u2 port0 */ 40 value = mtu3_readl(ibase, SSUSB_U2_CTRL(0)); 41 value |= SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS; 42 mtu3_writel(ibase, SSUSB_U2_CTRL(0), value); 43 44 /* 2. power on, enable u2 port0 and select its mode */ 45 value = mtu3_readl(ibase, SSUSB_U2_CTRL(0)); 46 value &= ~(SSUSB_U2_PORT_PDN | SSUSB_U2_PORT_DIS); 47 value = tohost ? (value | SSUSB_U2_PORT_HOST_SEL) : 48 (value & (~SSUSB_U2_PORT_HOST_SEL)); 49 mtu3_writel(ibase, SSUSB_U2_CTRL(0), value); 50 } else { 51 /* 1. power off and disable u3 port0 */ 52 value = mtu3_readl(ibase, SSUSB_U3_CTRL(0)); 53 value |= SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS; 54 mtu3_writel(ibase, SSUSB_U3_CTRL(0), value); 55 56 /* 2. power on, enable u3 port0 and select its mode */ 57 value = mtu3_readl(ibase, SSUSB_U3_CTRL(0)); 58 value &= ~(SSUSB_U3_PORT_PDN | SSUSB_U3_PORT_DIS); 59 value = tohost ? (value | SSUSB_U3_PORT_HOST_SEL) : 60 (value & (~SSUSB_U3_PORT_HOST_SEL)); 61 mtu3_writel(ibase, SSUSB_U3_CTRL(0), value); 62 } 63 64 return 0; 65} 66 67static void switch_port_to_host(struct ssusb_mtk *ssusb) 68{ 69 u32 check_clk = 0; 70 71 dev_dbg(ssusb->dev, "%s\n", __func__); 72 73 ssusb_port0_switch(ssusb, USB2_PORT, true); 74 75 if (ssusb->otg_switch.is_u3_drd) { 76 ssusb_port0_switch(ssusb, USB3_PORT, true); 77 check_clk = SSUSB_U3_MAC_RST_B_STS; 78 } 79 80 ssusb_check_clocks(ssusb, check_clk); 81 82 /* after all clocks are stable */ 83 toggle_opstate(ssusb); 84} 85 86static void switch_port_to_device(struct ssusb_mtk *ssusb) 87{ 88 u32 check_clk = 0; 89 90 dev_dbg(ssusb->dev, "%s\n", __func__); 91 92 ssusb_port0_switch(ssusb, USB2_PORT, false); 93 94 if (ssusb->otg_switch.is_u3_drd) { 95 ssusb_port0_switch(ssusb, USB3_PORT, false); 96 check_clk = SSUSB_U3_MAC_RST_B_STS; 97 } 98 99 ssusb_check_clocks(ssusb, check_clk); 100} 101 102int ssusb_set_vbus(struct otg_switch_mtk *otg_sx, int is_on) 103{ 104 struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx); 105 struct regulator *vbus = otg_sx->vbus; 106 int ret; 107 108 /* vbus is optional */ 109 if (!vbus) 110 return 0; 111 112 dev_dbg(ssusb->dev, "%s: turn %s\n", __func__, is_on ? "on" : "off"); 113 114 if (is_on) { 115 ret = regulator_enable(vbus); 116 if (ret) { 117 dev_err(ssusb->dev, "vbus regulator enable failed\n"); 118 return ret; 119 } 120 } else { 121 regulator_disable(vbus); 122 } 123 124 return 0; 125} 126 127static void ssusb_mode_sw_work(struct work_struct *work) 128{ 129 struct otg_switch_mtk *otg_sx = 130 container_of(work, struct otg_switch_mtk, dr_work); 131 struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx); 132 struct mtu3 *mtu = ssusb->u3d; 133 enum usb_role desired_role = otg_sx->desired_role; 134 enum usb_role current_role; 135 136 current_role = ssusb->is_host ? USB_ROLE_HOST : USB_ROLE_DEVICE; 137 138 if (desired_role == USB_ROLE_NONE) { 139 /* the default mode is host as probe does */ 140 desired_role = USB_ROLE_HOST; 141 if (otg_sx->default_role == USB_ROLE_DEVICE) 142 desired_role = USB_ROLE_DEVICE; 143 } 144 145 if (current_role == desired_role) 146 return; 147 148 dev_dbg(ssusb->dev, "set role : %s\n", usb_role_string(desired_role)); 149 mtu3_dbg_trace(ssusb->dev, "set role : %s", usb_role_string(desired_role)); 150 pm_runtime_get_sync(ssusb->dev); 151 152 switch (desired_role) { 153 case USB_ROLE_HOST: 154 ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_HOST); 155 mtu3_stop(mtu); 156 switch_port_to_host(ssusb); 157 ssusb_set_vbus(otg_sx, 1); 158 ssusb->is_host = true; 159 break; 160 case USB_ROLE_DEVICE: 161 ssusb_set_force_mode(ssusb, MTU3_DR_FORCE_DEVICE); 162 ssusb->is_host = false; 163 ssusb_set_vbus(otg_sx, 0); 164 switch_port_to_device(ssusb); 165 mtu3_start(mtu); 166 break; 167 case USB_ROLE_NONE: 168 default: 169 dev_err(ssusb->dev, "invalid role\n"); 170 } 171 pm_runtime_put(ssusb->dev); 172} 173 174static void ssusb_set_mode(struct otg_switch_mtk *otg_sx, enum usb_role role) 175{ 176 struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx); 177 178 if (ssusb->dr_mode != USB_DR_MODE_OTG) 179 return; 180 181 otg_sx->desired_role = role; 182 queue_work(system_freezable_wq, &otg_sx->dr_work); 183} 184 185static int ssusb_id_notifier(struct notifier_block *nb, 186 unsigned long event, void *ptr) 187{ 188 struct otg_switch_mtk *otg_sx = 189 container_of(nb, struct otg_switch_mtk, id_nb); 190 191 ssusb_set_mode(otg_sx, event ? USB_ROLE_HOST : USB_ROLE_DEVICE); 192 193 return NOTIFY_DONE; 194} 195 196static int ssusb_extcon_register(struct otg_switch_mtk *otg_sx) 197{ 198 struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx); 199 struct extcon_dev *edev = otg_sx->edev; 200 int ret; 201 202 /* extcon is optional */ 203 if (!edev) 204 return 0; 205 206 otg_sx->id_nb.notifier_call = ssusb_id_notifier; 207 ret = devm_extcon_register_notifier(ssusb->dev, edev, EXTCON_USB_HOST, 208 &otg_sx->id_nb); 209 if (ret < 0) { 210 dev_err(ssusb->dev, "failed to register notifier for USB-HOST\n"); 211 return ret; 212 } 213 214 ret = extcon_get_state(edev, EXTCON_USB_HOST); 215 dev_dbg(ssusb->dev, "EXTCON_USB_HOST: %d\n", ret); 216 217 /* default as host, switch to device mode if needed */ 218 if (!ret) 219 ssusb_set_mode(otg_sx, USB_ROLE_DEVICE); 220 221 return 0; 222} 223 224/* 225 * We provide an interface via debugfs to switch between host and device modes 226 * depending on user input. 227 * This is useful in special cases, such as uses TYPE-A receptacle but also 228 * wants to support dual-role mode. 229 */ 230void ssusb_mode_switch(struct ssusb_mtk *ssusb, int to_host) 231{ 232 struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; 233 234 ssusb_set_mode(otg_sx, to_host ? USB_ROLE_HOST : USB_ROLE_DEVICE); 235} 236 237void ssusb_set_force_mode(struct ssusb_mtk *ssusb, 238 enum mtu3_dr_force_mode mode) 239{ 240 u32 value; 241 242 value = mtu3_readl(ssusb->ippc_base, SSUSB_U2_CTRL(0)); 243 switch (mode) { 244 case MTU3_DR_FORCE_DEVICE: 245 value |= SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG; 246 break; 247 case MTU3_DR_FORCE_HOST: 248 value |= SSUSB_U2_PORT_FORCE_IDDIG; 249 value &= ~SSUSB_U2_PORT_RG_IDDIG; 250 break; 251 case MTU3_DR_FORCE_NONE: 252 value &= ~(SSUSB_U2_PORT_FORCE_IDDIG | SSUSB_U2_PORT_RG_IDDIG); 253 break; 254 default: 255 return; 256 } 257 mtu3_writel(ssusb->ippc_base, SSUSB_U2_CTRL(0), value); 258} 259 260static int ssusb_role_sw_set(struct usb_role_switch *sw, enum usb_role role) 261{ 262 struct ssusb_mtk *ssusb = usb_role_switch_get_drvdata(sw); 263 struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; 264 265 ssusb_set_mode(otg_sx, role); 266 267 return 0; 268} 269 270static enum usb_role ssusb_role_sw_get(struct usb_role_switch *sw) 271{ 272 struct ssusb_mtk *ssusb = usb_role_switch_get_drvdata(sw); 273 274 return ssusb->is_host ? USB_ROLE_HOST : USB_ROLE_DEVICE; 275} 276 277static int ssusb_role_sw_register(struct otg_switch_mtk *otg_sx) 278{ 279 struct usb_role_switch_desc role_sx_desc = { 0 }; 280 struct ssusb_mtk *ssusb = otg_sx_to_ssusb(otg_sx); 281 struct device *dev = ssusb->dev; 282 enum usb_dr_mode mode; 283 284 if (!otg_sx->role_sw_used) 285 return 0; 286 287 mode = usb_get_role_switch_default_mode(dev); 288 if (mode == USB_DR_MODE_PERIPHERAL) 289 otg_sx->default_role = USB_ROLE_DEVICE; 290 else 291 otg_sx->default_role = USB_ROLE_HOST; 292 293 role_sx_desc.set = ssusb_role_sw_set; 294 role_sx_desc.get = ssusb_role_sw_get; 295 role_sx_desc.fwnode = dev_fwnode(dev); 296 role_sx_desc.driver_data = ssusb; 297 otg_sx->role_sw = usb_role_switch_register(dev, &role_sx_desc); 298 if (IS_ERR(otg_sx->role_sw)) 299 return PTR_ERR(otg_sx->role_sw); 300 301 ssusb_set_mode(otg_sx, otg_sx->default_role); 302 303 return 0; 304} 305 306int ssusb_otg_switch_init(struct ssusb_mtk *ssusb) 307{ 308 struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; 309 int ret = 0; 310 311 INIT_WORK(&otg_sx->dr_work, ssusb_mode_sw_work); 312 313 if (otg_sx->manual_drd_enabled) 314 ssusb_dr_debugfs_init(ssusb); 315 else if (otg_sx->role_sw_used) 316 ret = ssusb_role_sw_register(otg_sx); 317 else 318 ret = ssusb_extcon_register(otg_sx); 319 320 return ret; 321} 322 323void ssusb_otg_switch_exit(struct ssusb_mtk *ssusb) 324{ 325 struct otg_switch_mtk *otg_sx = &ssusb->otg_switch; 326 327 cancel_work_sync(&otg_sx->dr_work); 328 usb_role_switch_unregister(otg_sx->role_sw); 329}