mod.c (8319B)
1// SPDX-License-Identifier: GPL-1.0+ 2/* 3 * Renesas USB driver 4 * 5 * Copyright (C) 2011 Renesas Solutions Corp. 6 * Copyright (C) 2019 Renesas Electronics Corporation 7 * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> 8 */ 9#include <linux/interrupt.h> 10 11#include "common.h" 12#include "mod.h" 13 14/* 15 * autonomy 16 * 17 * these functions are used if platform doesn't have external phy. 18 * -> there is no "notify_hotplug" callback from platform 19 * -> call "notify_hotplug" by itself 20 * -> use own interrupt to connect/disconnect 21 * -> it mean module clock is always ON 22 * ~~~~~~~~~~~~~~~~~~~~~~~~~ 23 */ 24static int usbhsm_autonomy_get_vbus(struct platform_device *pdev) 25{ 26 struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); 27 28 return VBSTS & usbhs_read(priv, INTSTS0); 29} 30 31static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv, 32 struct usbhs_irq_state *irq_state) 33{ 34 struct platform_device *pdev = usbhs_priv_to_pdev(priv); 35 36 usbhsc_schedule_notify_hotplug(pdev); 37 38 return 0; 39} 40 41void usbhs_mod_autonomy_mode(struct usbhs_priv *priv) 42{ 43 struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); 44 45 info->irq_vbus = usbhsm_autonomy_irq_vbus; 46 info->get_vbus = usbhsm_autonomy_get_vbus; 47 48 usbhs_irq_callback_update(priv, NULL); 49} 50 51void usbhs_mod_non_autonomy_mode(struct usbhs_priv *priv) 52{ 53 struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); 54 55 info->get_vbus = priv->pfunc->get_vbus; 56} 57 58/* 59 * host / gadget functions 60 * 61 * renesas_usbhs host/gadget can register itself by below functions. 62 * these functions are called when probe 63 * 64 */ 65void usbhs_mod_register(struct usbhs_priv *priv, struct usbhs_mod *mod, int id) 66{ 67 struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); 68 69 info->mod[id] = mod; 70 mod->priv = priv; 71} 72 73struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id) 74{ 75 struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); 76 struct usbhs_mod *ret = NULL; 77 78 switch (id) { 79 case USBHS_HOST: 80 case USBHS_GADGET: 81 ret = info->mod[id]; 82 break; 83 } 84 85 return ret; 86} 87 88int usbhs_mod_is_host(struct usbhs_priv *priv) 89{ 90 struct usbhs_mod *mod = usbhs_mod_get_current(priv); 91 struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); 92 93 if (!mod) 94 return -EINVAL; 95 96 return info->mod[USBHS_HOST] == mod; 97} 98 99struct usbhs_mod *usbhs_mod_get_current(struct usbhs_priv *priv) 100{ 101 struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); 102 103 return info->curt; 104} 105 106int usbhs_mod_change(struct usbhs_priv *priv, int id) 107{ 108 struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); 109 struct usbhs_mod *mod = NULL; 110 int ret = 0; 111 112 /* id < 0 mean no current */ 113 switch (id) { 114 case USBHS_HOST: 115 case USBHS_GADGET: 116 mod = info->mod[id]; 117 break; 118 default: 119 ret = -EINVAL; 120 } 121 info->curt = mod; 122 123 return ret; 124} 125 126static irqreturn_t usbhs_interrupt(int irq, void *data); 127int usbhs_mod_probe(struct usbhs_priv *priv) 128{ 129 struct device *dev = usbhs_priv_to_dev(priv); 130 int ret; 131 132 /* 133 * install host/gadget driver 134 */ 135 ret = usbhs_mod_host_probe(priv); 136 if (ret < 0) 137 return ret; 138 139 ret = usbhs_mod_gadget_probe(priv); 140 if (ret < 0) 141 goto mod_init_host_err; 142 143 /* irq settings */ 144 ret = devm_request_irq(dev, priv->irq, usbhs_interrupt, 145 0, dev_name(dev), priv); 146 if (ret) { 147 dev_err(dev, "irq request err\n"); 148 goto mod_init_gadget_err; 149 } 150 151 return ret; 152 153mod_init_gadget_err: 154 usbhs_mod_gadget_remove(priv); 155mod_init_host_err: 156 usbhs_mod_host_remove(priv); 157 158 return ret; 159} 160 161void usbhs_mod_remove(struct usbhs_priv *priv) 162{ 163 usbhs_mod_host_remove(priv); 164 usbhs_mod_gadget_remove(priv); 165} 166 167/* 168 * status functions 169 */ 170int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state) 171{ 172 return (int)irq_state->intsts0 & DVSQ_MASK; 173} 174 175int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state) 176{ 177 /* 178 * return value 179 * 180 * IDLE_SETUP_STAGE 181 * READ_DATA_STAGE 182 * READ_STATUS_STAGE 183 * WRITE_DATA_STAGE 184 * WRITE_STATUS_STAGE 185 * NODATA_STATUS_STAGE 186 * SEQUENCE_ERROR 187 */ 188 return (int)irq_state->intsts0 & CTSQ_MASK; 189} 190 191static int usbhs_status_get_each_irq(struct usbhs_priv *priv, 192 struct usbhs_irq_state *state) 193{ 194 struct usbhs_mod *mod = usbhs_mod_get_current(priv); 195 u16 intenb0, intenb1; 196 unsigned long flags; 197 198 /******************** spin lock ********************/ 199 usbhs_lock(priv, flags); 200 state->intsts0 = usbhs_read(priv, INTSTS0); 201 intenb0 = usbhs_read(priv, INTENB0); 202 203 if (usbhs_mod_is_host(priv)) { 204 state->intsts1 = usbhs_read(priv, INTSTS1); 205 intenb1 = usbhs_read(priv, INTENB1); 206 } else { 207 state->intsts1 = intenb1 = 0; 208 } 209 210 /* mask */ 211 if (mod) { 212 state->brdysts = usbhs_read(priv, BRDYSTS); 213 state->nrdysts = usbhs_read(priv, NRDYSTS); 214 state->bempsts = usbhs_read(priv, BEMPSTS); 215 216 state->bempsts &= mod->irq_bempsts; 217 state->brdysts &= mod->irq_brdysts; 218 } 219 usbhs_unlock(priv, flags); 220 /******************** spin unlock ******************/ 221 222 return 0; 223} 224 225/* 226 * interrupt 227 */ 228#define INTSTS0_MAGIC 0xF800 /* acknowledge magical interrupt sources */ 229#define INTSTS1_MAGIC 0xA870 /* acknowledge magical interrupt sources */ 230static irqreturn_t usbhs_interrupt(int irq, void *data) 231{ 232 struct usbhs_priv *priv = data; 233 struct usbhs_irq_state irq_state; 234 235 if (usbhs_status_get_each_irq(priv, &irq_state) < 0) 236 return IRQ_NONE; 237 238 /* 239 * clear interrupt 240 * 241 * The hardware is _very_ picky to clear interrupt bit. 242 * Especially INTSTS0_MAGIC, INTSTS1_MAGIC value. 243 * 244 * see 245 * "Operation" 246 * - "Control Transfer (DCP)" 247 * - Function :: VALID bit should 0 248 */ 249 usbhs_write(priv, INTSTS0, ~irq_state.intsts0 & INTSTS0_MAGIC); 250 if (usbhs_mod_is_host(priv)) 251 usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC); 252 253 /* 254 * The driver should not clear the xxxSTS after the line of 255 * "call irq callback functions" because each "if" statement is 256 * possible to call the callback function for avoiding any side effects. 257 */ 258 if (irq_state.intsts0 & BRDY) 259 usbhs_write(priv, BRDYSTS, ~irq_state.brdysts); 260 usbhs_write(priv, NRDYSTS, ~irq_state.nrdysts); 261 if (irq_state.intsts0 & BEMP) 262 usbhs_write(priv, BEMPSTS, ~irq_state.bempsts); 263 264 /* 265 * call irq callback functions 266 * see also 267 * usbhs_irq_setting_update 268 */ 269 270 /* INTSTS0 */ 271 if (irq_state.intsts0 & VBINT) 272 usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state); 273 274 if (irq_state.intsts0 & DVST) 275 usbhs_mod_call(priv, irq_dev_state, priv, &irq_state); 276 277 if (irq_state.intsts0 & CTRT) 278 usbhs_mod_call(priv, irq_ctrl_stage, priv, &irq_state); 279 280 if (irq_state.intsts0 & BEMP) 281 usbhs_mod_call(priv, irq_empty, priv, &irq_state); 282 283 if (irq_state.intsts0 & BRDY) 284 usbhs_mod_call(priv, irq_ready, priv, &irq_state); 285 286 if (usbhs_mod_is_host(priv)) { 287 /* INTSTS1 */ 288 if (irq_state.intsts1 & ATTCH) 289 usbhs_mod_call(priv, irq_attch, priv, &irq_state); 290 291 if (irq_state.intsts1 & DTCH) 292 usbhs_mod_call(priv, irq_dtch, priv, &irq_state); 293 294 if (irq_state.intsts1 & SIGN) 295 usbhs_mod_call(priv, irq_sign, priv, &irq_state); 296 297 if (irq_state.intsts1 & SACK) 298 usbhs_mod_call(priv, irq_sack, priv, &irq_state); 299 } 300 return IRQ_HANDLED; 301} 302 303void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod) 304{ 305 u16 intenb0 = 0; 306 u16 intenb1 = 0; 307 struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv); 308 309 /* 310 * BEMPENB/BRDYENB are picky. 311 * below method is required 312 * 313 * - clear INTSTS0 314 * - update BEMPENB/BRDYENB 315 * - update INTSTS0 316 */ 317 usbhs_write(priv, INTENB0, 0); 318 if (usbhs_mod_is_host(priv)) 319 usbhs_write(priv, INTENB1, 0); 320 321 usbhs_write(priv, BEMPENB, 0); 322 usbhs_write(priv, BRDYENB, 0); 323 324 /* 325 * see also 326 * usbhs_interrupt 327 */ 328 329 if (info->irq_vbus) 330 intenb0 |= VBSE; 331 332 if (mod) { 333 /* 334 * INTSTS0 335 */ 336 if (mod->irq_ctrl_stage) 337 intenb0 |= CTRE; 338 339 if (mod->irq_dev_state) 340 intenb0 |= DVSE; 341 342 if (mod->irq_empty && mod->irq_bempsts) { 343 usbhs_write(priv, BEMPENB, mod->irq_bempsts); 344 intenb0 |= BEMPE; 345 } 346 347 if (mod->irq_ready && mod->irq_brdysts) { 348 usbhs_write(priv, BRDYENB, mod->irq_brdysts); 349 intenb0 |= BRDYE; 350 } 351 352 if (usbhs_mod_is_host(priv)) { 353 /* 354 * INTSTS1 355 */ 356 if (mod->irq_attch) 357 intenb1 |= ATTCHE; 358 359 if (mod->irq_dtch) 360 intenb1 |= DTCHE; 361 362 if (mod->irq_sign) 363 intenb1 |= SIGNE; 364 365 if (mod->irq_sack) 366 intenb1 |= SACKE; 367 } 368 } 369 370 if (intenb0) 371 usbhs_write(priv, INTENB0, intenb0); 372 373 if (usbhs_mod_is_host(priv) && intenb1) 374 usbhs_write(priv, INTENB1, intenb1); 375}