Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-1.0+
0002 /*
0003  * Renesas USB driver
0004  *
0005  * Copyright (C) 2011 Renesas Solutions Corp.
0006  * Copyright (C) 2019 Renesas Electronics Corporation
0007  * Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
0008  */
0009 #include <linux/interrupt.h>
0010 
0011 #include "common.h"
0012 #include "mod.h"
0013 
0014 /*
0015  *      autonomy
0016  *
0017  * these functions are used if platform doesn't have external phy.
0018  *  -> there is no "notify_hotplug" callback from platform
0019  *  -> call "notify_hotplug" by itself
0020  *  -> use own interrupt to connect/disconnect
0021  *  -> it mean module clock is always ON
0022  *             ~~~~~~~~~~~~~~~~~~~~~~~~~
0023  */
0024 static int usbhsm_autonomy_get_vbus(struct platform_device *pdev)
0025 {
0026     struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev);
0027 
0028     return  VBSTS & usbhs_read(priv, INTSTS0);
0029 }
0030 
0031 static int usbhsm_autonomy_irq_vbus(struct usbhs_priv *priv,
0032                     struct usbhs_irq_state *irq_state)
0033 {
0034     struct platform_device *pdev = usbhs_priv_to_pdev(priv);
0035 
0036     usbhsc_schedule_notify_hotplug(pdev);
0037 
0038     return 0;
0039 }
0040 
0041 void usbhs_mod_autonomy_mode(struct usbhs_priv *priv)
0042 {
0043     struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
0044 
0045     info->irq_vbus = usbhsm_autonomy_irq_vbus;
0046     info->get_vbus = usbhsm_autonomy_get_vbus;
0047 
0048     usbhs_irq_callback_update(priv, NULL);
0049 }
0050 
0051 void usbhs_mod_non_autonomy_mode(struct usbhs_priv *priv)
0052 {
0053     struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
0054 
0055     info->get_vbus = priv->pfunc->get_vbus;
0056 }
0057 
0058 /*
0059  *      host / gadget functions
0060  *
0061  * renesas_usbhs host/gadget can register itself by below functions.
0062  * these functions are called when probe
0063  *
0064  */
0065 void usbhs_mod_register(struct usbhs_priv *priv, struct usbhs_mod *mod, int id)
0066 {
0067     struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
0068 
0069     info->mod[id]   = mod;
0070     mod->priv   = priv;
0071 }
0072 
0073 struct usbhs_mod *usbhs_mod_get(struct usbhs_priv *priv, int id)
0074 {
0075     struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
0076     struct usbhs_mod *ret = NULL;
0077 
0078     switch (id) {
0079     case USBHS_HOST:
0080     case USBHS_GADGET:
0081         ret = info->mod[id];
0082         break;
0083     }
0084 
0085     return ret;
0086 }
0087 
0088 int usbhs_mod_is_host(struct usbhs_priv *priv)
0089 {
0090     struct usbhs_mod *mod = usbhs_mod_get_current(priv);
0091     struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
0092 
0093     if (!mod)
0094         return -EINVAL;
0095 
0096     return info->mod[USBHS_HOST] == mod;
0097 }
0098 
0099 struct usbhs_mod *usbhs_mod_get_current(struct usbhs_priv *priv)
0100 {
0101     struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
0102 
0103     return info->curt;
0104 }
0105 
0106 int usbhs_mod_change(struct usbhs_priv *priv, int id)
0107 {
0108     struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
0109     struct usbhs_mod *mod = NULL;
0110     int ret = 0;
0111 
0112     /* id < 0 mean no current */
0113     switch (id) {
0114     case USBHS_HOST:
0115     case USBHS_GADGET:
0116         mod = info->mod[id];
0117         break;
0118     default:
0119         ret = -EINVAL;
0120     }
0121     info->curt = mod;
0122 
0123     return ret;
0124 }
0125 
0126 static irqreturn_t usbhs_interrupt(int irq, void *data);
0127 int usbhs_mod_probe(struct usbhs_priv *priv)
0128 {
0129     struct device *dev = usbhs_priv_to_dev(priv);
0130     int ret;
0131 
0132     /*
0133      * install host/gadget driver
0134      */
0135     ret = usbhs_mod_host_probe(priv);
0136     if (ret < 0)
0137         return ret;
0138 
0139     ret = usbhs_mod_gadget_probe(priv);
0140     if (ret < 0)
0141         goto mod_init_host_err;
0142 
0143     /* irq settings */
0144     ret = devm_request_irq(dev, priv->irq, usbhs_interrupt,
0145                    0, dev_name(dev), priv);
0146     if (ret) {
0147         dev_err(dev, "irq request err\n");
0148         goto mod_init_gadget_err;
0149     }
0150 
0151     return ret;
0152 
0153 mod_init_gadget_err:
0154     usbhs_mod_gadget_remove(priv);
0155 mod_init_host_err:
0156     usbhs_mod_host_remove(priv);
0157 
0158     return ret;
0159 }
0160 
0161 void usbhs_mod_remove(struct usbhs_priv *priv)
0162 {
0163     usbhs_mod_host_remove(priv);
0164     usbhs_mod_gadget_remove(priv);
0165 }
0166 
0167 /*
0168  *      status functions
0169  */
0170 int usbhs_status_get_device_state(struct usbhs_irq_state *irq_state)
0171 {
0172     return (int)irq_state->intsts0 & DVSQ_MASK;
0173 }
0174 
0175 int usbhs_status_get_ctrl_stage(struct usbhs_irq_state *irq_state)
0176 {
0177     /*
0178      * return value
0179      *
0180      * IDLE_SETUP_STAGE
0181      * READ_DATA_STAGE
0182      * READ_STATUS_STAGE
0183      * WRITE_DATA_STAGE
0184      * WRITE_STATUS_STAGE
0185      * NODATA_STATUS_STAGE
0186      * SEQUENCE_ERROR
0187      */
0188     return (int)irq_state->intsts0 & CTSQ_MASK;
0189 }
0190 
0191 static int usbhs_status_get_each_irq(struct usbhs_priv *priv,
0192                      struct usbhs_irq_state *state)
0193 {
0194     struct usbhs_mod *mod = usbhs_mod_get_current(priv);
0195     u16 intenb0, intenb1;
0196     unsigned long flags;
0197 
0198     /********************  spin lock ********************/
0199     usbhs_lock(priv, flags);
0200     state->intsts0 = usbhs_read(priv, INTSTS0);
0201     intenb0 = usbhs_read(priv, INTENB0);
0202 
0203     if (usbhs_mod_is_host(priv)) {
0204         state->intsts1 = usbhs_read(priv, INTSTS1);
0205         intenb1 = usbhs_read(priv, INTENB1);
0206     } else {
0207         state->intsts1 = intenb1 = 0;
0208     }
0209 
0210     /* mask */
0211     if (mod) {
0212         state->brdysts = usbhs_read(priv, BRDYSTS);
0213         state->nrdysts = usbhs_read(priv, NRDYSTS);
0214         state->bempsts = usbhs_read(priv, BEMPSTS);
0215 
0216         state->bempsts &= mod->irq_bempsts;
0217         state->brdysts &= mod->irq_brdysts;
0218     }
0219     usbhs_unlock(priv, flags);
0220     /********************  spin unlock ******************/
0221 
0222     return 0;
0223 }
0224 
0225 /*
0226  *      interrupt
0227  */
0228 #define INTSTS0_MAGIC 0xF800 /* acknowledge magical interrupt sources */
0229 #define INTSTS1_MAGIC 0xA870 /* acknowledge magical interrupt sources */
0230 static irqreturn_t usbhs_interrupt(int irq, void *data)
0231 {
0232     struct usbhs_priv *priv = data;
0233     struct usbhs_irq_state irq_state;
0234 
0235     if (usbhs_status_get_each_irq(priv, &irq_state) < 0)
0236         return IRQ_NONE;
0237 
0238     /*
0239      * clear interrupt
0240      *
0241      * The hardware is _very_ picky to clear interrupt bit.
0242      * Especially INTSTS0_MAGIC, INTSTS1_MAGIC value.
0243      *
0244      * see
0245      *  "Operation"
0246      *   - "Control Transfer (DCP)"
0247      *     - Function :: VALID bit should 0
0248      */
0249     usbhs_write(priv, INTSTS0, ~irq_state.intsts0 & INTSTS0_MAGIC);
0250     if (usbhs_mod_is_host(priv))
0251         usbhs_write(priv, INTSTS1, ~irq_state.intsts1 & INTSTS1_MAGIC);
0252 
0253     /*
0254      * The driver should not clear the xxxSTS after the line of
0255      * "call irq callback functions" because each "if" statement is
0256      * possible to call the callback function for avoiding any side effects.
0257      */
0258     if (irq_state.intsts0 & BRDY)
0259         usbhs_write(priv, BRDYSTS, ~irq_state.brdysts);
0260     usbhs_write(priv, NRDYSTS, ~irq_state.nrdysts);
0261     if (irq_state.intsts0 & BEMP)
0262         usbhs_write(priv, BEMPSTS, ~irq_state.bempsts);
0263 
0264     /*
0265      * call irq callback functions
0266      * see also
0267      *  usbhs_irq_setting_update
0268      */
0269 
0270     /* INTSTS0 */
0271     if (irq_state.intsts0 & VBINT)
0272         usbhs_mod_info_call(priv, irq_vbus, priv, &irq_state);
0273 
0274     if (irq_state.intsts0 & DVST)
0275         usbhs_mod_call(priv, irq_dev_state, priv, &irq_state);
0276 
0277     if (irq_state.intsts0 & CTRT)
0278         usbhs_mod_call(priv, irq_ctrl_stage, priv, &irq_state);
0279 
0280     if (irq_state.intsts0 & BEMP)
0281         usbhs_mod_call(priv, irq_empty, priv, &irq_state);
0282 
0283     if (irq_state.intsts0 & BRDY)
0284         usbhs_mod_call(priv, irq_ready, priv, &irq_state);
0285 
0286     if (usbhs_mod_is_host(priv)) {
0287         /* INTSTS1 */
0288         if (irq_state.intsts1 & ATTCH)
0289             usbhs_mod_call(priv, irq_attch, priv, &irq_state);
0290 
0291         if (irq_state.intsts1 & DTCH)
0292             usbhs_mod_call(priv, irq_dtch, priv, &irq_state);
0293 
0294         if (irq_state.intsts1 & SIGN)
0295             usbhs_mod_call(priv, irq_sign, priv, &irq_state);
0296 
0297         if (irq_state.intsts1 & SACK)
0298             usbhs_mod_call(priv, irq_sack, priv, &irq_state);
0299     }
0300     return IRQ_HANDLED;
0301 }
0302 
0303 void usbhs_irq_callback_update(struct usbhs_priv *priv, struct usbhs_mod *mod)
0304 {
0305     u16 intenb0 = 0;
0306     u16 intenb1 = 0;
0307     struct usbhs_mod_info *info = usbhs_priv_to_modinfo(priv);
0308 
0309     /*
0310      * BEMPENB/BRDYENB are picky.
0311      * below method is required
0312      *
0313      *  - clear  INTSTS0
0314      *  - update BEMPENB/BRDYENB
0315      *  - update INTSTS0
0316      */
0317     usbhs_write(priv, INTENB0, 0);
0318     if (usbhs_mod_is_host(priv))
0319         usbhs_write(priv, INTENB1, 0);
0320 
0321     usbhs_write(priv, BEMPENB, 0);
0322     usbhs_write(priv, BRDYENB, 0);
0323 
0324     /*
0325      * see also
0326      *  usbhs_interrupt
0327      */
0328 
0329     if (info->irq_vbus)
0330         intenb0 |= VBSE;
0331 
0332     if (mod) {
0333         /*
0334          * INTSTS0
0335          */
0336         if (mod->irq_ctrl_stage)
0337             intenb0 |= CTRE;
0338 
0339         if (mod->irq_dev_state)
0340             intenb0 |= DVSE;
0341 
0342         if (mod->irq_empty && mod->irq_bempsts) {
0343             usbhs_write(priv, BEMPENB, mod->irq_bempsts);
0344             intenb0 |= BEMPE;
0345         }
0346 
0347         if (mod->irq_ready && mod->irq_brdysts) {
0348             usbhs_write(priv, BRDYENB, mod->irq_brdysts);
0349             intenb0 |= BRDYE;
0350         }
0351 
0352         if (usbhs_mod_is_host(priv)) {
0353             /*
0354              * INTSTS1
0355              */
0356             if (mod->irq_attch)
0357                 intenb1 |= ATTCHE;
0358 
0359             if (mod->irq_dtch)
0360                 intenb1 |= DTCHE;
0361 
0362             if (mod->irq_sign)
0363                 intenb1 |= SIGNE;
0364 
0365             if (mod->irq_sack)
0366                 intenb1 |= SACKE;
0367         }
0368     }
0369 
0370     if (intenb0)
0371         usbhs_write(priv, INTENB0, intenb0);
0372 
0373     if (usbhs_mod_is_host(priv) && intenb1)
0374         usbhs_write(priv, INTENB1, intenb1);
0375 }