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