linux/drivers/usb/musb/ux500.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2010 ST-Ericsson AB
   3 * Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>
   4 *
   5 * Based on omap2430.c
   6 *
   7 * This program is free software; you can redistribute it and/or modify
   8 * it under the terms of the GNU General Public License as published by
   9 * the Free Software Foundation; either version 2 of the License, or
  10 * (at your option) any later version.
  11 *
  12 * This program is distributed in the hope that it will be useful,
  13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15 * GNU General Public License for more details.
  16 *
  17 * You should have received a copy of the GNU General Public License
  18 * along with this program; if not, write to the Free Software
  19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20 */
  21
  22#include <linux/module.h>
  23#include <linux/kernel.h>
  24#include <linux/init.h>
  25#include <linux/clk.h>
  26#include <linux/err.h>
  27#include <linux/io.h>
  28#include <linux/platform_device.h>
  29
  30#include "musb_core.h"
  31
  32struct ux500_glue {
  33        struct device           *dev;
  34        struct platform_device  *musb;
  35        struct clk              *clk;
  36};
  37#define glue_to_musb(g) platform_get_drvdata(g->musb)
  38
  39static irqreturn_t ux500_musb_interrupt(int irq, void *__hci)
  40{
  41        unsigned long   flags;
  42        irqreturn_t     retval = IRQ_NONE;
  43        struct musb     *musb = __hci;
  44
  45        spin_lock_irqsave(&musb->lock, flags);
  46
  47        musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB);
  48        musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX);
  49        musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX);
  50
  51        if (musb->int_usb || musb->int_tx || musb->int_rx)
  52                retval = musb_interrupt(musb);
  53
  54        spin_unlock_irqrestore(&musb->lock, flags);
  55
  56        return retval;
  57}
  58
  59static int ux500_musb_init(struct musb *musb)
  60{
  61        musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2);
  62        if (IS_ERR_OR_NULL(musb->xceiv)) {
  63                pr_err("HS USB OTG: no transceiver configured\n");
  64                return -EPROBE_DEFER;
  65        }
  66
  67        musb->isr = ux500_musb_interrupt;
  68
  69        return 0;
  70}
  71
  72static int ux500_musb_exit(struct musb *musb)
  73{
  74        usb_put_phy(musb->xceiv);
  75
  76        return 0;
  77}
  78
  79static const struct musb_platform_ops ux500_ops = {
  80        .init           = ux500_musb_init,
  81        .exit           = ux500_musb_exit,
  82};
  83
  84static int ux500_probe(struct platform_device *pdev)
  85{
  86        struct musb_hdrc_platform_data  *pdata = pdev->dev.platform_data;
  87        struct platform_device          *musb;
  88        struct ux500_glue               *glue;
  89        struct clk                      *clk;
  90        int                             ret = -ENOMEM;
  91
  92        glue = kzalloc(sizeof(*glue), GFP_KERNEL);
  93        if (!glue) {
  94                dev_err(&pdev->dev, "failed to allocate glue context\n");
  95                goto err0;
  96        }
  97
  98        musb = platform_device_alloc("musb-hdrc", PLATFORM_DEVID_AUTO);
  99        if (!musb) {
 100                dev_err(&pdev->dev, "failed to allocate musb device\n");
 101                goto err1;
 102        }
 103
 104        clk = clk_get(&pdev->dev, "usb");
 105        if (IS_ERR(clk)) {
 106                dev_err(&pdev->dev, "failed to get clock\n");
 107                ret = PTR_ERR(clk);
 108                goto err3;
 109        }
 110
 111        ret = clk_prepare_enable(clk);
 112        if (ret) {
 113                dev_err(&pdev->dev, "failed to enable clock\n");
 114                goto err4;
 115        }
 116
 117        musb->dev.parent                = &pdev->dev;
 118        musb->dev.dma_mask              = pdev->dev.dma_mask;
 119        musb->dev.coherent_dma_mask     = pdev->dev.coherent_dma_mask;
 120
 121        glue->dev                       = &pdev->dev;
 122        glue->musb                      = musb;
 123        glue->clk                       = clk;
 124
 125        pdata->platform_ops             = &ux500_ops;
 126
 127        platform_set_drvdata(pdev, glue);
 128
 129        ret = platform_device_add_resources(musb, pdev->resource,
 130                        pdev->num_resources);
 131        if (ret) {
 132                dev_err(&pdev->dev, "failed to add resources\n");
 133                goto err5;
 134        }
 135
 136        ret = platform_device_add_data(musb, pdata, sizeof(*pdata));
 137        if (ret) {
 138                dev_err(&pdev->dev, "failed to add platform_data\n");
 139                goto err5;
 140        }
 141
 142        ret = platform_device_add(musb);
 143        if (ret) {
 144                dev_err(&pdev->dev, "failed to register musb device\n");
 145                goto err5;
 146        }
 147
 148        return 0;
 149
 150err5:
 151        clk_disable_unprepare(clk);
 152
 153err4:
 154        clk_put(clk);
 155
 156err3:
 157        platform_device_put(musb);
 158
 159err1:
 160        kfree(glue);
 161
 162err0:
 163        return ret;
 164}
 165
 166static int ux500_remove(struct platform_device *pdev)
 167{
 168        struct ux500_glue       *glue = platform_get_drvdata(pdev);
 169
 170        platform_device_unregister(glue->musb);
 171        clk_disable_unprepare(glue->clk);
 172        clk_put(glue->clk);
 173        kfree(glue);
 174
 175        return 0;
 176}
 177
 178#ifdef CONFIG_PM
 179static int ux500_suspend(struct device *dev)
 180{
 181        struct ux500_glue       *glue = dev_get_drvdata(dev);
 182        struct musb             *musb = glue_to_musb(glue);
 183
 184        usb_phy_set_suspend(musb->xceiv, 1);
 185        clk_disable_unprepare(glue->clk);
 186
 187        return 0;
 188}
 189
 190static int ux500_resume(struct device *dev)
 191{
 192        struct ux500_glue       *glue = dev_get_drvdata(dev);
 193        struct musb             *musb = glue_to_musb(glue);
 194        int                     ret;
 195
 196        ret = clk_prepare_enable(glue->clk);
 197        if (ret) {
 198                dev_err(dev, "failed to enable clock\n");
 199                return ret;
 200        }
 201
 202        usb_phy_set_suspend(musb->xceiv, 0);
 203
 204        return 0;
 205}
 206
 207static const struct dev_pm_ops ux500_pm_ops = {
 208        .suspend        = ux500_suspend,
 209        .resume         = ux500_resume,
 210};
 211
 212#define DEV_PM_OPS      (&ux500_pm_ops)
 213#else
 214#define DEV_PM_OPS      NULL
 215#endif
 216
 217static struct platform_driver ux500_driver = {
 218        .probe          = ux500_probe,
 219        .remove         = ux500_remove,
 220        .driver         = {
 221                .name   = "musb-ux500",
 222                .pm     = DEV_PM_OPS,
 223        },
 224};
 225
 226MODULE_DESCRIPTION("UX500 MUSB Glue Layer");
 227MODULE_AUTHOR("Mian Yousaf Kaukab <mian.yousaf.kaukab@stericsson.com>");
 228MODULE_LICENSE("GPL v2");
 229module_platform_driver(ux500_driver);
 230