1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * otg.c - ChipIdea USB IP core OTG driver 4 * 5 * Copyright (C) 2013 Freescale Semiconductor, Inc. 6 * 7 * Author: Peter Chen 8 * 9 * This program is free software; you can redistribute it and/or modify 10 * it under the terms of the GNU General Public License version 2 as 11 * published by the Free Software Foundation. 12 */ 13 14 /* 15 * This file mainly handles otgsc register, OTG fsm operations for HNP and SRP 16 * are also included. 17 */ 18 19 #include <linux/usb/otg.h> 20 #include <linux/usb/gadget.h> 21 #include <linux/usb/chipidea.h> 22 23 #include "ci.h" 24 #include "bits.h" 25 #include "otg.h" 26 #include "otg_fsm.h" 27 28 /** 29 * hw_read_otgsc returns otgsc register bits value. 30 * @mask: bitfield mask 31 */ 32 u32 hw_read_otgsc(struct ci_hdrc *ci, u32 mask) 33 { 34 struct ci_hdrc_cable *cable; 35 u32 val = hw_read(ci, OP_OTGSC, mask); 36 37 /* 38 * If using extcon framework for VBUS and/or ID signal 39 * detection overwrite OTGSC register value 40 */ 41 cable = &ci->platdata->vbus_extcon; 42 if (!IS_ERR(cable->edev)) { 43 if (cable->changed) 44 val |= OTGSC_BSVIS; 45 else 46 val &= ~OTGSC_BSVIS; 47 48 if (cable->connected) 49 val |= OTGSC_BSV; 50 else 51 val &= ~OTGSC_BSV; 52 53 if (cable->enabled) 54 val |= OTGSC_BSVIE; 55 else 56 val &= ~OTGSC_BSVIE; 57 } 58 59 cable = &ci->platdata->id_extcon; 60 if (!IS_ERR(cable->edev)) { 61 if (cable->changed) 62 val |= OTGSC_IDIS; 63 else 64 val &= ~OTGSC_IDIS; 65 66 if (cable->connected) 67 val &= ~OTGSC_ID; /* host */ 68 else 69 val |= OTGSC_ID; /* device */ 70 71 if (cable->enabled) 72 val |= OTGSC_IDIE; 73 else 74 val &= ~OTGSC_IDIE; 75 } 76 77 return val & mask; 78 } 79 80 /** 81 * hw_write_otgsc updates target bits of OTGSC register. 82 * @mask: bitfield mask 83 * @data: to be written 84 */ 85 void hw_write_otgsc(struct ci_hdrc *ci, u32 mask, u32 data) 86 { 87 struct ci_hdrc_cable *cable; 88 89 cable = &ci->platdata->vbus_extcon; 90 if (!IS_ERR(cable->edev)) { 91 if (data & mask & OTGSC_BSVIS) 92 cable->changed = false; 93 94 /* Don't enable vbus interrupt if using external notifier */ 95 if (data & mask & OTGSC_BSVIE) { 96 cable->enabled = true; 97 data &= ~OTGSC_BSVIE; 98 } else if (mask & OTGSC_BSVIE) { 99 cable->enabled = false; 100 } 101 } 102 103 cable = &ci->platdata->id_extcon; 104 if (!IS_ERR(cable->edev)) { 105 if (data & mask & OTGSC_IDIS) 106 cable->changed = false; 107 108 /* Don't enable id interrupt if using external notifier */ 109 if (data & mask & OTGSC_IDIE) { 110 cable->enabled = true; 111 data &= ~OTGSC_IDIE; 112 } else if (mask & OTGSC_IDIE) { 113 cable->enabled = false; 114 } 115 } 116 117 hw_write(ci, OP_OTGSC, mask | OTGSC_INT_STATUS_BITS, data); 118 } 119 120 /** 121 * ci_otg_role - pick role based on ID pin state 122 * @ci: the controller 123 */ 124 enum ci_role ci_otg_role(struct ci_hdrc *ci) 125 { 126 enum ci_role role = hw_read_otgsc(ci, OTGSC_ID) 127 ? CI_ROLE_GADGET 128 : CI_ROLE_HOST; 129 130 return role; 131 } 132 133 void ci_handle_vbus_change(struct ci_hdrc *ci) 134 { 135 if (!ci->is_otg) 136 return; 137 138 if (hw_read_otgsc(ci, OTGSC_BSV) && !ci->vbus_active) 139 usb_gadget_vbus_connect(&ci->gadget); 140 else if (!hw_read_otgsc(ci, OTGSC_BSV) && ci->vbus_active) 141 usb_gadget_vbus_disconnect(&ci->gadget); 142 } 143 144 /** 145 * When we switch to device mode, the vbus value should be lower 146 * than OTGSC_BSV before connecting to host. 147 * 148 * @ci: the controller 149 * 150 * This function returns an error code if timeout 151 */ 152 static int hw_wait_vbus_lower_bsv(struct ci_hdrc *ci) 153 { 154 unsigned long elapse = jiffies + msecs_to_jiffies(5000); 155 u32 mask = OTGSC_BSV; 156 157 while (hw_read_otgsc(ci, mask)) { 158 if (time_after(jiffies, elapse)) { 159 dev_err(ci->dev, "timeout waiting for %08x in OTGSC\n", 160 mask); 161 return -ETIMEDOUT; 162 } 163 msleep(20); 164 } 165 166 return 0; 167 } 168 169 static void ci_handle_id_switch(struct ci_hdrc *ci) 170 { 171 enum ci_role role = ci_otg_role(ci); 172 173 if (role != ci->role) { 174 dev_dbg(ci->dev, "switching from %s to %s\n", 175 ci_role(ci)->name, ci->roles[role]->name); 176 177 ci_role_stop(ci); 178 179 if (role == CI_ROLE_GADGET && 180 IS_ERR(ci->platdata->vbus_extcon.edev)) 181 /* 182 * Wait vbus lower than OTGSC_BSV before connecting 183 * to host. If connecting status is from an external 184 * connector instead of register, we don't need to 185 * care vbus on the board, since it will not affect 186 * external connector status. 187 */ 188 hw_wait_vbus_lower_bsv(ci); 189 190 ci_role_start(ci, role); 191 /* vbus change may have already occurred */ 192 if (role == CI_ROLE_GADGET) 193 ci_handle_vbus_change(ci); 194 } 195 } 196 /** 197 * ci_otg_work - perform otg (vbus/id) event handle 198 * @work: work struct 199 */ 200 static void ci_otg_work(struct work_struct *work) 201 { 202 struct ci_hdrc *ci = container_of(work, struct ci_hdrc, work); 203 204 if (ci_otg_is_fsm_mode(ci) && !ci_otg_fsm_work(ci)) { 205 enable_irq(ci->irq); 206 return; 207 } 208 209 pm_runtime_get_sync(ci->dev); 210 if (ci->id_event) { 211 ci->id_event = false; 212 ci_handle_id_switch(ci); 213 } else if (ci->b_sess_valid_event) { 214 ci->b_sess_valid_event = false; 215 ci_handle_vbus_change(ci); 216 } else 217 dev_err(ci->dev, "unexpected event occurs at %s\n", __func__); 218 pm_runtime_put_sync(ci->dev); 219 220 enable_irq(ci->irq); 221 } 222 223 224 /** 225 * ci_hdrc_otg_init - initialize otg struct 226 * ci: the controller 227 */ 228 int ci_hdrc_otg_init(struct ci_hdrc *ci) 229 { 230 INIT_WORK(&ci->work, ci_otg_work); 231 ci->wq = create_freezable_workqueue("ci_otg"); 232 if (!ci->wq) { 233 dev_err(ci->dev, "can't create workqueue\n"); 234 return -ENODEV; 235 } 236 237 if (ci_otg_is_fsm_mode(ci)) 238 return ci_hdrc_otg_fsm_init(ci); 239 240 return 0; 241 } 242 243 /** 244 * ci_hdrc_otg_destroy - destroy otg struct 245 * ci: the controller 246 */ 247 void ci_hdrc_otg_destroy(struct ci_hdrc *ci) 248 { 249 if (ci->wq) { 250 flush_workqueue(ci->wq); 251 destroy_workqueue(ci->wq); 252 } 253 /* Disable all OTG irq and clear status */ 254 hw_write_otgsc(ci, OTGSC_INT_EN_BITS | OTGSC_INT_STATUS_BITS, 255 OTGSC_INT_STATUS_BITS); 256 if (ci_otg_is_fsm_mode(ci)) 257 ci_hdrc_otg_fsm_remove(ci); 258 } 259