linux/drivers/usb/musb/omap2430.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Copyright (C) 2005-2007 by Texas Instruments
   4 * Some code has been taken from tusb6010.c
   5 * Copyrights for that are attributable to:
   6 * Copyright (C) 2006 Nokia Corporation
   7 * Tony Lindgren <tony@atomide.com>
   8 *
   9 * This file is part of the Inventra Controller Driver for Linux.
  10 */
  11#include <linux/module.h>
  12#include <linux/kernel.h>
  13#include <linux/sched.h>
  14#include <linux/init.h>
  15#include <linux/list.h>
  16#include <linux/io.h>
  17#include <linux/of.h>
  18#include <linux/platform_device.h>
  19#include <linux/dma-mapping.h>
  20#include <linux/pm_runtime.h>
  21#include <linux/err.h>
  22#include <linux/delay.h>
  23#include <linux/usb/musb.h>
  24#include <linux/phy/omap_control_phy.h>
  25#include <linux/of_platform.h>
  26
  27#include "musb_core.h"
  28#include "omap2430.h"
  29
  30struct omap2430_glue {
  31        struct device           *dev;
  32        struct platform_device  *musb;
  33        enum musb_vbus_id_status status;
  34        struct work_struct      omap_musb_mailbox_work;
  35        struct device           *control_otghs;
  36};
  37#define glue_to_musb(g)         platform_get_drvdata(g->musb)
  38
  39static struct omap2430_glue     *_glue;
  40
  41static void omap2430_musb_set_vbus(struct musb *musb, int is_on)
  42{
  43        struct usb_otg  *otg = musb->xceiv->otg;
  44        u8              devctl;
  45        unsigned long timeout = jiffies + msecs_to_jiffies(1000);
  46        /* HDRC controls CPEN, but beware current surges during device
  47         * connect.  They can trigger transient overcurrent conditions
  48         * that must be ignored.
  49         */
  50
  51        devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
  52
  53        if (is_on) {
  54                if (musb->xceiv->otg->state == OTG_STATE_A_IDLE) {
  55                        int loops = 100;
  56                        /* start the session */
  57                        devctl |= MUSB_DEVCTL_SESSION;
  58                        musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
  59                        /*
  60                         * Wait for the musb to set as A device to enable the
  61                         * VBUS
  62                         */
  63                        while (musb_readb(musb->mregs, MUSB_DEVCTL) &
  64                               MUSB_DEVCTL_BDEVICE) {
  65
  66                                mdelay(5);
  67                                cpu_relax();
  68
  69                                if (time_after(jiffies, timeout)
  70                                    || loops-- <= 0) {
  71                                        dev_err(musb->controller,
  72                                        "configured as A device timeout");
  73                                        break;
  74                                }
  75                        }
  76
  77                        otg_set_vbus(otg, 1);
  78                } else {
  79                        musb->is_active = 1;
  80                        otg->default_a = 1;
  81                        musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
  82                        devctl |= MUSB_DEVCTL_SESSION;
  83                        MUSB_HST_MODE(musb);
  84                }
  85        } else {
  86                musb->is_active = 0;
  87
  88                /* NOTE:  we're skipping A_WAIT_VFALL -> A_IDLE and
  89                 * jumping right to B_IDLE...
  90                 */
  91
  92                otg->default_a = 0;
  93                musb->xceiv->otg->state = OTG_STATE_B_IDLE;
  94                devctl &= ~MUSB_DEVCTL_SESSION;
  95
  96                MUSB_DEV_MODE(musb);
  97        }
  98        musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
  99
 100        dev_dbg(musb->controller, "VBUS %s, devctl %02x "
 101                /* otg %3x conf %08x prcm %08x */ "\n",
 102                usb_otg_state_string(musb->xceiv->otg->state),
 103                musb_readb(musb->mregs, MUSB_DEVCTL));
 104}
 105
 106static inline void omap2430_low_level_exit(struct musb *musb)
 107{
 108        u32 l;
 109
 110        /* in any role */
 111        l = musb_readl(musb->mregs, OTG_FORCESTDBY);
 112        l |= ENABLEFORCE;       /* enable MSTANDBY */
 113        musb_writel(musb->mregs, OTG_FORCESTDBY, l);
 114}
 115
 116static inline void omap2430_low_level_init(struct musb *musb)
 117{
 118        u32 l;
 119
 120        l = musb_readl(musb->mregs, OTG_FORCESTDBY);
 121        l &= ~ENABLEFORCE;      /* disable MSTANDBY */
 122        musb_writel(musb->mregs, OTG_FORCESTDBY, l);
 123}
 124
 125static int omap2430_musb_mailbox(enum musb_vbus_id_status status)
 126{
 127        struct omap2430_glue    *glue = _glue;
 128
 129        if (!glue) {
 130                pr_err("%s: musb core is not yet initialized\n", __func__);
 131                return -EPROBE_DEFER;
 132        }
 133        glue->status = status;
 134
 135        if (!glue_to_musb(glue)) {
 136                pr_err("%s: musb core is not yet ready\n", __func__);
 137                return -EPROBE_DEFER;
 138        }
 139
 140        schedule_work(&glue->omap_musb_mailbox_work);
 141
 142        return 0;
 143}
 144
 145static void omap_musb_set_mailbox(struct omap2430_glue *glue)
 146{
 147        struct musb *musb = glue_to_musb(glue);
 148        struct musb_hdrc_platform_data *pdata =
 149                dev_get_platdata(musb->controller);
 150        struct omap_musb_board_data *data = pdata->board_data;
 151        struct usb_otg *otg = musb->xceiv->otg;
 152
 153        pm_runtime_get_sync(musb->controller);
 154        switch (glue->status) {
 155        case MUSB_ID_GROUND:
 156                dev_dbg(musb->controller, "ID GND\n");
 157
 158                otg->default_a = true;
 159                musb->xceiv->otg->state = OTG_STATE_A_IDLE;
 160                musb->xceiv->last_event = USB_EVENT_ID;
 161                if (musb->gadget_driver) {
 162                        omap_control_usb_set_mode(glue->control_otghs,
 163                                USB_MODE_HOST);
 164                        omap2430_musb_set_vbus(musb, 1);
 165                }
 166                break;
 167
 168        case MUSB_VBUS_VALID:
 169                dev_dbg(musb->controller, "VBUS Connect\n");
 170
 171                otg->default_a = false;
 172                musb->xceiv->otg->state = OTG_STATE_B_IDLE;
 173                musb->xceiv->last_event = USB_EVENT_VBUS;
 174                omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE);
 175                break;
 176
 177        case MUSB_ID_FLOAT:
 178        case MUSB_VBUS_OFF:
 179                dev_dbg(musb->controller, "VBUS Disconnect\n");
 180
 181                musb->xceiv->last_event = USB_EVENT_NONE;
 182                if (musb->gadget_driver)
 183                        omap2430_musb_set_vbus(musb, 0);
 184
 185                if (data->interface_type == MUSB_INTERFACE_UTMI)
 186                        otg_set_vbus(musb->xceiv->otg, 0);
 187
 188                omap_control_usb_set_mode(glue->control_otghs,
 189                        USB_MODE_DISCONNECT);
 190                break;
 191        default:
 192                dev_dbg(musb->controller, "ID float\n");
 193        }
 194        pm_runtime_mark_last_busy(musb->controller);
 195        pm_runtime_put_autosuspend(musb->controller);
 196        atomic_notifier_call_chain(&musb->xceiv->notifier,
 197                        musb->xceiv->last_event, NULL);
 198}
 199
 200
 201static void omap_musb_mailbox_work(struct work_struct *mailbox_work)
 202{
 203        struct omap2430_glue *glue = container_of(mailbox_work,
 204                                struct omap2430_glue, omap_musb_mailbox_work);
 205
 206        omap_musb_set_mailbox(glue);
 207}
 208
 209static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci)
 210{
 211        unsigned long   flags;
 212        irqreturn_t     retval = IRQ_NONE;
 213        struct musb     *musb = __hci;
 214
 215        spin_lock_irqsave(&musb->lock, flags);
 216
 217        musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
 218        musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
 219        musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
 220
 221        if (musb->int_usb || musb->int_tx || musb->int_rx)
 222                retval = musb_interrupt(musb);
 223
 224        spin_unlock_irqrestore(&musb->lock, flags);
 225
 226        return retval;
 227}
 228
 229static int omap2430_musb_init(struct musb *musb)
 230{
 231        u32 l;
 232        int status = 0;
 233        struct device *dev = musb->controller;
 234        struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
 235        struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
 236        struct omap_musb_board_data *data = plat->board_data;
 237
 238        /* We require some kind of external transceiver, hooked
 239         * up through ULPI.  TWL4030-family PMICs include one,
 240         * which needs a driver, drivers aren't always needed.
 241         */
 242        if (dev->parent->of_node) {
 243                musb->phy = devm_phy_get(dev->parent, "usb2-phy");
 244
 245                /* We can't totally remove musb->xceiv as of now because
 246                 * musb core uses xceiv.state and xceiv.otg. Once we have
 247                 * a separate state machine to handle otg, these can be moved
 248                 * out of xceiv and then we can start using the generic PHY
 249                 * framework
 250                 */
 251                musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent,
 252                    "usb-phy", 0);
 253        } else {
 254                musb->xceiv = devm_usb_get_phy_dev(dev, 0);
 255                musb->phy = devm_phy_get(dev, "usb");
 256        }
 257
 258        if (IS_ERR(musb->xceiv)) {
 259                status = PTR_ERR(musb->xceiv);
 260
 261                if (status == -ENXIO)
 262                        return status;
 263
 264                dev_dbg(dev, "HS USB OTG: no transceiver configured\n");
 265                return -EPROBE_DEFER;
 266        }
 267
 268        if (IS_ERR(musb->phy)) {
 269                dev_err(dev, "HS USB OTG: no PHY configured\n");
 270                return PTR_ERR(musb->phy);
 271        }
 272        musb->isr = omap2430_musb_interrupt;
 273        phy_init(musb->phy);
 274        phy_power_on(musb->phy);
 275
 276        l = musb_readl(musb->mregs, OTG_INTERFSEL);
 277
 278        if (data->interface_type == MUSB_INTERFACE_UTMI) {
 279                /* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
 280                l &= ~ULPI_12PIN;       /* Disable ULPI */
 281                l |= UTMI_8BIT;         /* Enable UTMI  */
 282        } else {
 283                l |= ULPI_12PIN;
 284        }
 285
 286        musb_writel(musb->mregs, OTG_INTERFSEL, l);
 287
 288        dev_dbg(dev, "HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
 289                        "sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
 290                        musb_readl(musb->mregs, OTG_REVISION),
 291                        musb_readl(musb->mregs, OTG_SYSCONFIG),
 292                        musb_readl(musb->mregs, OTG_SYSSTATUS),
 293                        musb_readl(musb->mregs, OTG_INTERFSEL),
 294                        musb_readl(musb->mregs, OTG_SIMENABLE));
 295
 296        if (glue->status != MUSB_UNKNOWN)
 297                omap_musb_set_mailbox(glue);
 298
 299        return 0;
 300}
 301
 302static void omap2430_musb_enable(struct musb *musb)
 303{
 304        u8              devctl;
 305        unsigned long timeout = jiffies + msecs_to_jiffies(1000);
 306        struct device *dev = musb->controller;
 307        struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
 308        struct musb_hdrc_platform_data *pdata = dev_get_platdata(dev);
 309        struct omap_musb_board_data *data = pdata->board_data;
 310
 311
 312        switch (glue->status) {
 313
 314        case MUSB_ID_GROUND:
 315                omap_control_usb_set_mode(glue->control_otghs, USB_MODE_HOST);
 316                if (data->interface_type != MUSB_INTERFACE_UTMI)
 317                        break;
 318                devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
 319                /* start the session */
 320                devctl |= MUSB_DEVCTL_SESSION;
 321                musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
 322                while (musb_readb(musb->mregs, MUSB_DEVCTL) &
 323                                MUSB_DEVCTL_BDEVICE) {
 324                        cpu_relax();
 325
 326                        if (time_after(jiffies, timeout)) {
 327                                dev_err(dev, "configured as A device timeout");
 328                                break;
 329                        }
 330                }
 331                break;
 332
 333        case MUSB_VBUS_VALID:
 334                omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE);
 335                break;
 336
 337        default:
 338                break;
 339        }
 340}
 341
 342static void omap2430_musb_disable(struct musb *musb)
 343{
 344        struct device *dev = musb->controller;
 345        struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
 346
 347        if (glue->status != MUSB_UNKNOWN)
 348                omap_control_usb_set_mode(glue->control_otghs,
 349                        USB_MODE_DISCONNECT);
 350}
 351
 352static int omap2430_musb_exit(struct musb *musb)
 353{
 354        struct device *dev = musb->controller;
 355        struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
 356
 357        omap2430_low_level_exit(musb);
 358        phy_power_off(musb->phy);
 359        phy_exit(musb->phy);
 360        musb->phy = NULL;
 361        cancel_work_sync(&glue->omap_musb_mailbox_work);
 362
 363        return 0;
 364}
 365
 366static const struct musb_platform_ops omap2430_ops = {
 367        .quirks         = MUSB_DMA_INVENTRA,
 368#ifdef CONFIG_USB_INVENTRA_DMA
 369        .dma_init       = musbhs_dma_controller_create,
 370        .dma_exit       = musbhs_dma_controller_destroy,
 371#endif
 372        .init           = omap2430_musb_init,
 373        .exit           = omap2430_musb_exit,
 374
 375        .set_vbus       = omap2430_musb_set_vbus,
 376
 377        .enable         = omap2430_musb_enable,
 378        .disable        = omap2430_musb_disable,
 379
 380        .phy_callback   = omap2430_musb_mailbox,
 381};
 382
 383static u64 omap2430_dmamask = DMA_BIT_MASK(32);
 384
 385static int omap2430_probe(struct platform_device *pdev)
 386{
 387        struct resource                 musb_resources[3];
 388        struct musb_hdrc_platform_data  *pdata = dev_get_platdata(&pdev->dev);
 389        struct omap_musb_board_data     *data;
 390        struct platform_device          *musb;
 391        struct omap2430_glue            *glue;
 392        struct device_node              *np = pdev->dev.of_node;
 393        struct musb_hdrc_config         *config;
 394        int                             ret = -ENOMEM, val;
 395
 396        glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
 397        if (!glue)
 398                goto err0;
 399
 400        musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
 401        if (!musb) {
 402                dev_err(&pdev->dev, "failed to allocate musb device\n");
 403                goto err0;
 404        }
 405
 406        musb->dev.parent                = &pdev->dev;
 407        musb->dev.dma_mask              = &omap2430_dmamask;
 408        musb->dev.coherent_dma_mask     = omap2430_dmamask;
 409
 410        glue->dev                       = &pdev->dev;
 411        glue->musb                      = musb;
 412        glue->status                    = MUSB_UNKNOWN;
 413        glue->control_otghs = ERR_PTR(-ENODEV);
 414
 415        if (np) {
 416                struct device_node *control_node;
 417                struct platform_device *control_pdev;
 418
 419                pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
 420                if (!pdata)
 421                        goto err2;
 422
 423                data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
 424                if (!data)
 425                        goto err2;
 426
 427                config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
 428                if (!config)
 429                        goto err2;
 430
 431                of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
 432                of_property_read_u32(np, "interface-type",
 433                                                (u32 *)&data->interface_type);
 434                of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
 435                of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
 436                of_property_read_u32(np, "power", (u32 *)&pdata->power);
 437
 438                ret = of_property_read_u32(np, "multipoint", &val);
 439                if (!ret && val)
 440                        config->multipoint = true;
 441
 442                pdata->board_data       = data;
 443                pdata->config           = config;
 444
 445                control_node = of_parse_phandle(np, "ctrl-module", 0);
 446                if (control_node) {
 447                        control_pdev = of_find_device_by_node(control_node);
 448                        if (!control_pdev) {
 449                                dev_err(&pdev->dev, "Failed to get control device\n");
 450                                ret = -EINVAL;
 451                                goto err2;
 452                        }
 453                        glue->control_otghs = &control_pdev->dev;
 454                }
 455        }
 456        pdata->platform_ops             = &omap2430_ops;
 457
 458        platform_set_drvdata(pdev, glue);
 459
 460        /*
 461         * REVISIT if we ever have two instances of the wrapper, we will be
 462         * in big trouble
 463         */
 464        _glue   = glue;
 465
 466        INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work);
 467
 468        memset(musb_resources, 0x00, sizeof(*musb_resources) *
 469                        ARRAY_SIZE(musb_resources));
 470
 471        musb_resources[0].name = pdev->resource[0].name;
 472        musb_resources[0].start = pdev->resource[0].start;
 473        musb_resources[0].end = pdev->resource[0].end;
 474        musb_resources[0].flags = pdev->resource[0].flags;
 475
 476        musb_resources[1].name = pdev->resource[1].name;
 477        musb_resources[1].start = pdev->resource[1].start;
 478        musb_resources[1].end = pdev->resource[1].end;
 479        musb_resources[1].flags = pdev->resource[1].flags;
 480
 481        musb_resources[2].name = pdev->resource[2].name;
 482        musb_resources[2].start = pdev->resource[2].start;
 483        musb_resources[2].end = pdev->resource[2].end;
 484        musb_resources[2].flags = pdev->resource[2].flags;
 485
 486        ret = platform_device_add_resources(musb, musb_resources,
 487                        ARRAY_SIZE(musb_resources));
 488        if (ret) {
 489                dev_err(&pdev->dev, "failed to add resources\n");
 490                goto err2;
 491        }
 492
 493        ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
 494        if (ret) {
 495                dev_err(&pdev->dev, "failed to add platform_data\n");
 496                goto err2;
 497        }
 498
 499        pm_runtime_enable(glue->dev);
 500
 501        ret = platform_device_add(musb);
 502        if (ret) {
 503                dev_err(&pdev->dev, "failed to register musb device\n");
 504                goto err3;
 505        }
 506
 507        return 0;
 508
 509err3:
 510        pm_runtime_disable(glue->dev);
 511
 512err2:
 513        platform_device_put(musb);
 514
 515err0:
 516        return ret;
 517}
 518
 519static int omap2430_remove(struct platform_device *pdev)
 520{
 521        struct omap2430_glue *glue = platform_get_drvdata(pdev);
 522
 523        platform_device_unregister(glue->musb);
 524        pm_runtime_disable(glue->dev);
 525
 526        return 0;
 527}
 528
 529#ifdef CONFIG_PM
 530
 531static int omap2430_runtime_suspend(struct device *dev)
 532{
 533        struct omap2430_glue            *glue = dev_get_drvdata(dev);
 534        struct musb                     *musb = glue_to_musb(glue);
 535
 536        if (!musb)
 537                return 0;
 538
 539        musb->context.otg_interfsel = musb_readl(musb->mregs,
 540                                                 OTG_INTERFSEL);
 541
 542        omap2430_low_level_exit(musb);
 543
 544        return 0;
 545}
 546
 547static int omap2430_runtime_resume(struct device *dev)
 548{
 549        struct omap2430_glue            *glue = dev_get_drvdata(dev);
 550        struct musb                     *musb = glue_to_musb(glue);
 551
 552        if (!musb)
 553                return 0;
 554
 555        omap2430_low_level_init(musb);
 556        musb_writel(musb->mregs, OTG_INTERFSEL,
 557                    musb->context.otg_interfsel);
 558
 559        return 0;
 560}
 561
 562static const struct dev_pm_ops omap2430_pm_ops = {
 563        .runtime_suspend = omap2430_runtime_suspend,
 564        .runtime_resume = omap2430_runtime_resume,
 565};
 566
 567#define DEV_PM_OPS      (&omap2430_pm_ops)
 568#else
 569#define DEV_PM_OPS      NULL
 570#endif
 571
 572#ifdef CONFIG_OF
 573static const struct of_device_id omap2430_id_table[] = {
 574        {
 575                .compatible = "ti,omap4-musb"
 576        },
 577        {
 578                .compatible = "ti,omap3-musb"
 579        },
 580        {},
 581};
 582MODULE_DEVICE_TABLE(of, omap2430_id_table);
 583#endif
 584
 585static struct platform_driver omap2430_driver = {
 586        .probe          = omap2430_probe,
 587        .remove         = omap2430_remove,
 588        .driver         = {
 589                .name   = "musb-omap2430",
 590                .pm     = DEV_PM_OPS,
 591                .of_match_table = of_match_ptr(omap2430_id_table),
 592        },
 593};
 594
 595module_platform_driver(omap2430_driver);
 596
 597MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
 598MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
 599MODULE_LICENSE("GPL v2");
 600