Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2005-2007 by Texas Instruments
0004  * Some code has been taken from tusb6010.c
0005  * Copyrights for that are attributable to:
0006  * Copyright (C) 2006 Nokia Corporation
0007  * Tony Lindgren <tony@atomide.com>
0008  *
0009  * This file is part of the Inventra Controller Driver for Linux.
0010  */
0011 #include <linux/module.h>
0012 #include <linux/kernel.h>
0013 #include <linux/sched.h>
0014 #include <linux/init.h>
0015 #include <linux/list.h>
0016 #include <linux/io.h>
0017 #include <linux/of.h>
0018 #include <linux/platform_device.h>
0019 #include <linux/dma-mapping.h>
0020 #include <linux/pm_runtime.h>
0021 #include <linux/err.h>
0022 #include <linux/delay.h>
0023 #include <linux/usb/musb.h>
0024 #include <linux/phy/omap_control_phy.h>
0025 #include <linux/of_platform.h>
0026 
0027 #include "musb_core.h"
0028 #include "omap2430.h"
0029 
0030 struct omap2430_glue {
0031     struct device       *dev;
0032     struct platform_device  *musb;
0033     enum musb_vbus_id_status status;
0034     struct work_struct  omap_musb_mailbox_work;
0035     struct device       *control_otghs;
0036     unsigned int        is_runtime_suspended:1;
0037     unsigned int        needs_resume:1;
0038     unsigned int        phy_suspended:1;
0039 };
0040 #define glue_to_musb(g)     platform_get_drvdata(g->musb)
0041 
0042 static struct omap2430_glue *_glue;
0043 
0044 static inline void omap2430_low_level_exit(struct musb *musb)
0045 {
0046     u32 l;
0047 
0048     /* in any role */
0049     l = musb_readl(musb->mregs, OTG_FORCESTDBY);
0050     l |= ENABLEFORCE;   /* enable MSTANDBY */
0051     musb_writel(musb->mregs, OTG_FORCESTDBY, l);
0052 }
0053 
0054 static inline void omap2430_low_level_init(struct musb *musb)
0055 {
0056     u32 l;
0057 
0058     l = musb_readl(musb->mregs, OTG_FORCESTDBY);
0059     l &= ~ENABLEFORCE;  /* disable MSTANDBY */
0060     musb_writel(musb->mregs, OTG_FORCESTDBY, l);
0061 }
0062 
0063 static int omap2430_musb_mailbox(enum musb_vbus_id_status status)
0064 {
0065     struct omap2430_glue    *glue = _glue;
0066 
0067     if (!glue) {
0068         pr_err("%s: musb core is not yet initialized\n", __func__);
0069         return -EPROBE_DEFER;
0070     }
0071     glue->status = status;
0072 
0073     if (!glue_to_musb(glue)) {
0074         pr_err("%s: musb core is not yet ready\n", __func__);
0075         return -EPROBE_DEFER;
0076     }
0077 
0078     schedule_work(&glue->omap_musb_mailbox_work);
0079 
0080     return 0;
0081 }
0082 
0083 /*
0084  * HDRC controls CPEN, but beware current surges during device connect.
0085  * They can trigger transient overcurrent conditions that must be ignored.
0086  *
0087  * Note that we're skipping A_WAIT_VFALL -> A_IDLE and jumping right to B_IDLE
0088  * as set by musb_set_peripheral().
0089  */
0090 static void omap_musb_set_mailbox(struct omap2430_glue *glue)
0091 {
0092     struct musb *musb = glue_to_musb(glue);
0093     int error;
0094 
0095     pm_runtime_get_sync(musb->controller);
0096 
0097     dev_dbg(musb->controller, "VBUS %s, devctl %02x\n",
0098         usb_otg_state_string(musb->xceiv->otg->state),
0099         musb_readb(musb->mregs, MUSB_DEVCTL));
0100 
0101     switch (glue->status) {
0102     case MUSB_ID_GROUND:
0103         dev_dbg(musb->controller, "ID GND\n");
0104         switch (musb->xceiv->otg->state) {
0105         case OTG_STATE_A_IDLE:
0106             error = musb_set_host(musb);
0107             if (error)
0108                 break;
0109             musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE;
0110             fallthrough;
0111         case OTG_STATE_A_WAIT_VRISE:
0112         case OTG_STATE_A_WAIT_BCON:
0113         case OTG_STATE_A_HOST:
0114             /*
0115              * On multiple ID ground interrupts just keep enabling
0116              * VBUS. At least cpcap VBUS shuts down otherwise.
0117              */
0118             otg_set_vbus(musb->xceiv->otg, 1);
0119             break;
0120         default:
0121             musb->xceiv->otg->state = OTG_STATE_A_IDLE;
0122             musb->xceiv->last_event = USB_EVENT_ID;
0123             if (musb->gadget_driver) {
0124                 omap_control_usb_set_mode(glue->control_otghs,
0125                               USB_MODE_HOST);
0126                 otg_set_vbus(musb->xceiv->otg, 1);
0127             }
0128             break;
0129         }
0130         break;
0131 
0132     case MUSB_VBUS_VALID:
0133         dev_dbg(musb->controller, "VBUS Connect\n");
0134 
0135         musb->xceiv->otg->state = OTG_STATE_B_IDLE;
0136         musb->xceiv->last_event = USB_EVENT_VBUS;
0137         omap_control_usb_set_mode(glue->control_otghs, USB_MODE_DEVICE);
0138         break;
0139 
0140     case MUSB_ID_FLOAT:
0141     case MUSB_VBUS_OFF:
0142         dev_dbg(musb->controller, "VBUS Disconnect\n");
0143 
0144         musb->xceiv->last_event = USB_EVENT_NONE;
0145         musb_set_peripheral(musb);
0146         otg_set_vbus(musb->xceiv->otg, 0);
0147         omap_control_usb_set_mode(glue->control_otghs,
0148             USB_MODE_DISCONNECT);
0149         break;
0150     default:
0151         dev_dbg(musb->controller, "ID float\n");
0152     }
0153     pm_runtime_mark_last_busy(musb->controller);
0154     pm_runtime_put_autosuspend(musb->controller);
0155     atomic_notifier_call_chain(&musb->xceiv->notifier,
0156             musb->xceiv->last_event, NULL);
0157 }
0158 
0159 
0160 static void omap_musb_mailbox_work(struct work_struct *mailbox_work)
0161 {
0162     struct omap2430_glue *glue = container_of(mailbox_work,
0163                 struct omap2430_glue, omap_musb_mailbox_work);
0164 
0165     omap_musb_set_mailbox(glue);
0166 }
0167 
0168 static irqreturn_t omap2430_musb_interrupt(int irq, void *__hci)
0169 {
0170     unsigned long   flags;
0171     irqreturn_t     retval = IRQ_NONE;
0172     struct musb     *musb = __hci;
0173 
0174     spin_lock_irqsave(&musb->lock, flags);
0175 
0176     musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
0177     musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
0178     musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
0179 
0180     if (musb->int_usb || musb->int_tx || musb->int_rx)
0181         retval = musb_interrupt(musb);
0182 
0183     spin_unlock_irqrestore(&musb->lock, flags);
0184 
0185     return retval;
0186 }
0187 
0188 static int omap2430_musb_init(struct musb *musb)
0189 {
0190     u32 l;
0191     int status = 0;
0192     struct device *dev = musb->controller;
0193     struct musb_hdrc_platform_data *plat = dev_get_platdata(dev);
0194     struct omap_musb_board_data *data = plat->board_data;
0195 
0196     /* We require some kind of external transceiver, hooked
0197      * up through ULPI.  TWL4030-family PMICs include one,
0198      * which needs a driver, drivers aren't always needed.
0199      */
0200     musb->phy = devm_phy_get(dev->parent, "usb2-phy");
0201 
0202     /* We can't totally remove musb->xceiv as of now because
0203      * musb core uses xceiv.state and xceiv.otg. Once we have
0204      * a separate state machine to handle otg, these can be moved
0205      * out of xceiv and then we can start using the generic PHY
0206      * framework
0207      */
0208     musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, "usb-phy", 0);
0209 
0210     if (IS_ERR(musb->xceiv)) {
0211         status = PTR_ERR(musb->xceiv);
0212 
0213         if (status == -ENXIO)
0214             return status;
0215 
0216         dev_dbg(dev, "HS USB OTG: no transceiver configured\n");
0217         return -EPROBE_DEFER;
0218     }
0219 
0220     if (IS_ERR(musb->phy)) {
0221         dev_err(dev, "HS USB OTG: no PHY configured\n");
0222         return PTR_ERR(musb->phy);
0223     }
0224     musb->isr = omap2430_musb_interrupt;
0225     phy_init(musb->phy);
0226     phy_power_on(musb->phy);
0227 
0228     l = musb_readl(musb->mregs, OTG_INTERFSEL);
0229 
0230     if (data->interface_type == MUSB_INTERFACE_UTMI) {
0231         /* OMAP4 uses Internal PHY GS70 which uses UTMI interface */
0232         l &= ~ULPI_12PIN;       /* Disable ULPI */
0233         l |= UTMI_8BIT;         /* Enable UTMI  */
0234     } else {
0235         l |= ULPI_12PIN;
0236     }
0237 
0238     musb_writel(musb->mregs, OTG_INTERFSEL, l);
0239 
0240     dev_dbg(dev, "HS USB OTG: revision 0x%x, sysconfig 0x%02x, "
0241             "sysstatus 0x%x, intrfsel 0x%x, simenable  0x%x\n",
0242             musb_readl(musb->mregs, OTG_REVISION),
0243             musb_readl(musb->mregs, OTG_SYSCONFIG),
0244             musb_readl(musb->mregs, OTG_SYSSTATUS),
0245             musb_readl(musb->mregs, OTG_INTERFSEL),
0246             musb_readl(musb->mregs, OTG_SIMENABLE));
0247 
0248     return 0;
0249 }
0250 
0251 static void omap2430_musb_enable(struct musb *musb)
0252 {
0253     struct device *dev = musb->controller;
0254     struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
0255 
0256     if (glue->status == MUSB_UNKNOWN)
0257         glue->status = MUSB_VBUS_OFF;
0258     omap_musb_set_mailbox(glue);
0259 }
0260 
0261 static void omap2430_musb_disable(struct musb *musb)
0262 {
0263     struct device *dev = musb->controller;
0264     struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
0265 
0266     if (glue->status != MUSB_UNKNOWN)
0267         omap_control_usb_set_mode(glue->control_otghs,
0268             USB_MODE_DISCONNECT);
0269 }
0270 
0271 static int omap2430_musb_exit(struct musb *musb)
0272 {
0273     struct device *dev = musb->controller;
0274     struct omap2430_glue *glue = dev_get_drvdata(dev->parent);
0275 
0276     omap2430_low_level_exit(musb);
0277     phy_power_off(musb->phy);
0278     phy_exit(musb->phy);
0279     musb->phy = NULL;
0280     cancel_work_sync(&glue->omap_musb_mailbox_work);
0281 
0282     return 0;
0283 }
0284 
0285 static const struct musb_platform_ops omap2430_ops = {
0286     .quirks     = MUSB_DMA_INVENTRA,
0287 #ifdef CONFIG_USB_INVENTRA_DMA
0288     .dma_init   = musbhs_dma_controller_create,
0289     .dma_exit   = musbhs_dma_controller_destroy,
0290 #endif
0291     .init       = omap2430_musb_init,
0292     .exit       = omap2430_musb_exit,
0293 
0294     .enable     = omap2430_musb_enable,
0295     .disable    = omap2430_musb_disable,
0296 
0297     .phy_callback   = omap2430_musb_mailbox,
0298 };
0299 
0300 static u64 omap2430_dmamask = DMA_BIT_MASK(32);
0301 
0302 static int omap2430_probe(struct platform_device *pdev)
0303 {
0304     struct musb_hdrc_platform_data  *pdata = dev_get_platdata(&pdev->dev);
0305     struct omap_musb_board_data *data;
0306     struct platform_device      *musb;
0307     struct omap2430_glue        *glue;
0308     struct device_node      *np = pdev->dev.of_node;
0309     struct musb_hdrc_config     *config;
0310     struct device_node      *control_node;
0311     struct platform_device      *control_pdev;
0312     int             ret = -ENOMEM, val;
0313 
0314     if (!np)
0315         return -ENODEV;
0316 
0317     glue = devm_kzalloc(&pdev->dev, sizeof(*glue), GFP_KERNEL);
0318     if (!glue)
0319         goto err0;
0320 
0321     musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
0322     if (!musb) {
0323         dev_err(&pdev->dev, "failed to allocate musb device\n");
0324         goto err0;
0325     }
0326 
0327     musb->dev.parent        = &pdev->dev;
0328     musb->dev.dma_mask      = &omap2430_dmamask;
0329     musb->dev.coherent_dma_mask = omap2430_dmamask;
0330 
0331     glue->dev           = &pdev->dev;
0332     glue->musb          = musb;
0333     glue->status            = MUSB_UNKNOWN;
0334     glue->control_otghs = ERR_PTR(-ENODEV);
0335 
0336     pdata = devm_kzalloc(&pdev->dev, sizeof(*pdata), GFP_KERNEL);
0337     if (!pdata)
0338         goto err2;
0339 
0340     data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
0341     if (!data)
0342         goto err2;
0343 
0344     config = devm_kzalloc(&pdev->dev, sizeof(*config), GFP_KERNEL);
0345     if (!config)
0346         goto err2;
0347 
0348     of_property_read_u32(np, "mode", (u32 *)&pdata->mode);
0349     of_property_read_u32(np, "interface-type",
0350             (u32 *)&data->interface_type);
0351     of_property_read_u32(np, "num-eps", (u32 *)&config->num_eps);
0352     of_property_read_u32(np, "ram-bits", (u32 *)&config->ram_bits);
0353     of_property_read_u32(np, "power", (u32 *)&pdata->power);
0354 
0355     ret = of_property_read_u32(np, "multipoint", &val);
0356     if (!ret && val)
0357         config->multipoint = true;
0358 
0359     pdata->board_data   = data;
0360     pdata->config       = config;
0361 
0362     control_node = of_parse_phandle(np, "ctrl-module", 0);
0363     if (control_node) {
0364         control_pdev = of_find_device_by_node(control_node);
0365         of_node_put(control_node);
0366         if (!control_pdev) {
0367             dev_err(&pdev->dev, "Failed to get control device\n");
0368             ret = -EINVAL;
0369             goto err2;
0370         }
0371         glue->control_otghs = &control_pdev->dev;
0372     }
0373 
0374     pdata->platform_ops     = &omap2430_ops;
0375 
0376     platform_set_drvdata(pdev, glue);
0377 
0378     /*
0379      * REVISIT if we ever have two instances of the wrapper, we will be
0380      * in big trouble
0381      */
0382     _glue   = glue;
0383 
0384     INIT_WORK(&glue->omap_musb_mailbox_work, omap_musb_mailbox_work);
0385 
0386     ret = platform_device_add_resources(musb, pdev->resource, pdev->num_resources);
0387     if (ret) {
0388         dev_err(&pdev->dev, "failed to add resources\n");
0389         goto err2;
0390     }
0391 
0392     ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
0393     if (ret) {
0394         dev_err(&pdev->dev, "failed to add platform_data\n");
0395         goto err2;
0396     }
0397 
0398     pm_runtime_enable(glue->dev);
0399 
0400     ret = platform_device_add(musb);
0401     if (ret) {
0402         dev_err(&pdev->dev, "failed to register musb device\n");
0403         goto err3;
0404     }
0405 
0406     return 0;
0407 
0408 err3:
0409     pm_runtime_disable(glue->dev);
0410 
0411 err2:
0412     platform_device_put(musb);
0413 
0414 err0:
0415     return ret;
0416 }
0417 
0418 static int omap2430_remove(struct platform_device *pdev)
0419 {
0420     struct omap2430_glue *glue = platform_get_drvdata(pdev);
0421 
0422     platform_device_unregister(glue->musb);
0423     pm_runtime_disable(glue->dev);
0424 
0425     return 0;
0426 }
0427 
0428 #ifdef CONFIG_PM
0429 
0430 static int omap2430_runtime_suspend(struct device *dev)
0431 {
0432     struct omap2430_glue        *glue = dev_get_drvdata(dev);
0433     struct musb         *musb = glue_to_musb(glue);
0434 
0435     if (!musb)
0436         return 0;
0437 
0438     musb->context.otg_interfsel = musb_readl(musb->mregs,
0439                          OTG_INTERFSEL);
0440 
0441     omap2430_low_level_exit(musb);
0442 
0443     if (!glue->phy_suspended) {
0444         phy_power_off(musb->phy);
0445         phy_exit(musb->phy);
0446     }
0447 
0448     glue->is_runtime_suspended = 1;
0449 
0450     return 0;
0451 }
0452 
0453 static int omap2430_runtime_resume(struct device *dev)
0454 {
0455     struct omap2430_glue        *glue = dev_get_drvdata(dev);
0456     struct musb         *musb = glue_to_musb(glue);
0457 
0458     if (!musb)
0459         return 0;
0460 
0461     if (!glue->phy_suspended) {
0462         phy_init(musb->phy);
0463         phy_power_on(musb->phy);
0464     }
0465 
0466     omap2430_low_level_init(musb);
0467     musb_writel(musb->mregs, OTG_INTERFSEL,
0468             musb->context.otg_interfsel);
0469 
0470     /* Wait for musb to get oriented. Otherwise we can get babble */
0471     usleep_range(200000, 250000);
0472 
0473     glue->is_runtime_suspended = 0;
0474 
0475     return 0;
0476 }
0477 
0478 /* I2C and SPI PHYs need to be suspended before the glue layer */
0479 static int omap2430_suspend(struct device *dev)
0480 {
0481     struct omap2430_glue *glue = dev_get_drvdata(dev);
0482     struct musb *musb = glue_to_musb(glue);
0483 
0484     phy_power_off(musb->phy);
0485     phy_exit(musb->phy);
0486     glue->phy_suspended = 1;
0487 
0488     return 0;
0489 }
0490 
0491 /* Glue layer needs to be suspended after musb_suspend() */
0492 static int omap2430_suspend_late(struct device *dev)
0493 {
0494     struct omap2430_glue *glue = dev_get_drvdata(dev);
0495 
0496     if (glue->is_runtime_suspended)
0497         return 0;
0498 
0499     glue->needs_resume = 1;
0500 
0501     return omap2430_runtime_suspend(dev);
0502 }
0503 
0504 static int omap2430_resume_early(struct device *dev)
0505 {
0506     struct omap2430_glue *glue = dev_get_drvdata(dev);
0507 
0508     if (!glue->needs_resume)
0509         return 0;
0510 
0511     glue->needs_resume = 0;
0512 
0513     return omap2430_runtime_resume(dev);
0514 }
0515 
0516 static int omap2430_resume(struct device *dev)
0517 {
0518     struct omap2430_glue *glue = dev_get_drvdata(dev);
0519     struct musb *musb = glue_to_musb(glue);
0520 
0521     phy_init(musb->phy);
0522     phy_power_on(musb->phy);
0523     glue->phy_suspended = 0;
0524 
0525     return 0;
0526 }
0527 
0528 static const struct dev_pm_ops omap2430_pm_ops = {
0529     .runtime_suspend = omap2430_runtime_suspend,
0530     .runtime_resume = omap2430_runtime_resume,
0531     .suspend = omap2430_suspend,
0532     .suspend_late = omap2430_suspend_late,
0533     .resume_early = omap2430_resume_early,
0534     .resume = omap2430_resume,
0535 };
0536 
0537 #define DEV_PM_OPS  (&omap2430_pm_ops)
0538 #else
0539 #define DEV_PM_OPS  NULL
0540 #endif
0541 
0542 #ifdef CONFIG_OF
0543 static const struct of_device_id omap2430_id_table[] = {
0544     {
0545         .compatible = "ti,omap4-musb"
0546     },
0547     {
0548         .compatible = "ti,omap3-musb"
0549     },
0550     {},
0551 };
0552 MODULE_DEVICE_TABLE(of, omap2430_id_table);
0553 #endif
0554 
0555 static struct platform_driver omap2430_driver = {
0556     .probe      = omap2430_probe,
0557     .remove     = omap2430_remove,
0558     .driver     = {
0559         .name   = "musb-omap2430",
0560         .pm = DEV_PM_OPS,
0561         .of_match_table = of_match_ptr(omap2430_id_table),
0562     },
0563 };
0564 
0565 module_platform_driver(omap2430_driver);
0566 
0567 MODULE_DESCRIPTION("OMAP2PLUS MUSB Glue Layer");
0568 MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
0569 MODULE_LICENSE("GPL v2");