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