linux/drivers/usb/dwc3/dwc3-pci.c
<<
>>
Prefs
   1/**
   2 * dwc3-pci.c - PCI Specific glue layer
   3 *
   4 * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com
   5 *
   6 * Authors: Felipe Balbi <balbi@ti.com>,
   7 *          Sebastian Andrzej Siewior <bigeasy@linutronix.de>
   8 *
   9 * This program is free software: you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2  of
  11 * the License as published by the Free Software Foundation.
  12 *
  13 * This program is distributed in the hope that it will be useful,
  14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16 * GNU General Public License for more details.
  17 */
  18
  19#include <linux/kernel.h>
  20#include <linux/module.h>
  21#include <linux/slab.h>
  22#include <linux/pci.h>
  23#include <linux/platform_device.h>
  24
  25#include <linux/usb/otg.h>
  26#include <linux/usb/usb_phy_generic.h>
  27
  28#include "platform_data.h"
  29
  30/* FIXME define these in <linux/pci_ids.h> */
  31#define PCI_VENDOR_ID_SYNOPSYS          0x16c3
  32#define PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3 0xabcd
  33#define PCI_DEVICE_ID_INTEL_BYT         0x0f37
  34#define PCI_DEVICE_ID_INTEL_MRFLD       0x119e
  35#define PCI_DEVICE_ID_INTEL_BSW         0x22B7
  36#define PCI_DEVICE_ID_INTEL_SPTLP       0x9d30
  37#define PCI_DEVICE_ID_INTEL_SPTH        0xa130
  38
  39struct dwc3_pci {
  40        struct device           *dev;
  41        struct platform_device  *dwc3;
  42        struct platform_device  *usb2_phy;
  43        struct platform_device  *usb3_phy;
  44};
  45
  46static int dwc3_pci_register_phys(struct dwc3_pci *glue)
  47{
  48        struct usb_phy_generic_platform_data pdata;
  49        struct platform_device  *pdev;
  50        int                     ret;
  51
  52        memset(&pdata, 0x00, sizeof(pdata));
  53
  54        pdev = platform_device_alloc("usb_phy_generic", 0);
  55        if (!pdev)
  56                return -ENOMEM;
  57
  58        glue->usb2_phy = pdev;
  59        pdata.type = USB_PHY_TYPE_USB2;
  60        pdata.gpio_reset = -1;
  61
  62        ret = platform_device_add_data(glue->usb2_phy, &pdata, sizeof(pdata));
  63        if (ret)
  64                goto err1;
  65
  66        pdev = platform_device_alloc("usb_phy_generic", 1);
  67        if (!pdev) {
  68                ret = -ENOMEM;
  69                goto err1;
  70        }
  71
  72        glue->usb3_phy = pdev;
  73        pdata.type = USB_PHY_TYPE_USB3;
  74
  75        ret = platform_device_add_data(glue->usb3_phy, &pdata, sizeof(pdata));
  76        if (ret)
  77                goto err2;
  78
  79        ret = platform_device_add(glue->usb2_phy);
  80        if (ret)
  81                goto err2;
  82
  83        ret = platform_device_add(glue->usb3_phy);
  84        if (ret)
  85                goto err3;
  86
  87        return 0;
  88
  89err3:
  90        platform_device_del(glue->usb2_phy);
  91
  92err2:
  93        platform_device_put(glue->usb3_phy);
  94
  95err1:
  96        platform_device_put(glue->usb2_phy);
  97
  98        return ret;
  99}
 100
 101static int dwc3_pci_probe(struct pci_dev *pci,
 102                const struct pci_device_id *id)
 103{
 104        struct resource         res[2];
 105        struct platform_device  *dwc3;
 106        struct dwc3_pci         *glue;
 107        int                     ret;
 108        struct device           *dev = &pci->dev;
 109        struct dwc3_platform_data dwc3_pdata;
 110
 111        memset(&dwc3_pdata, 0x00, sizeof(dwc3_pdata));
 112
 113        glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
 114        if (!glue)
 115                return -ENOMEM;
 116
 117        glue->dev = dev;
 118
 119        ret = pcim_enable_device(pci);
 120        if (ret) {
 121                dev_err(dev, "failed to enable pci device\n");
 122                return -ENODEV;
 123        }
 124
 125        pci_set_master(pci);
 126
 127        ret = dwc3_pci_register_phys(glue);
 128        if (ret) {
 129                dev_err(dev, "couldn't register PHYs\n");
 130                return ret;
 131        }
 132
 133        dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
 134        if (!dwc3) {
 135                dev_err(dev, "couldn't allocate dwc3 device\n");
 136                return -ENOMEM;
 137        }
 138
 139        memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
 140
 141        res[0].start    = pci_resource_start(pci, 0);
 142        res[0].end      = pci_resource_end(pci, 0);
 143        res[0].name     = "dwc_usb3";
 144        res[0].flags    = IORESOURCE_MEM;
 145
 146        res[1].start    = pci->irq;
 147        res[1].name     = "dwc_usb3";
 148        res[1].flags    = IORESOURCE_IRQ;
 149
 150        if (pci->vendor == PCI_VENDOR_ID_AMD &&
 151                        pci->device == PCI_DEVICE_ID_AMD_NL_USB) {
 152                dwc3_pdata.has_lpm_erratum = true;
 153                dwc3_pdata.lpm_nyet_threshold = 0xf;
 154
 155                dwc3_pdata.u2exit_lfps_quirk = true;
 156                dwc3_pdata.u2ss_inp3_quirk = true;
 157                dwc3_pdata.req_p1p2p3_quirk = true;
 158                dwc3_pdata.del_p1p2p3_quirk = true;
 159                dwc3_pdata.del_phy_power_chg_quirk = true;
 160                dwc3_pdata.lfps_filter_quirk = true;
 161                dwc3_pdata.rx_detect_poll_quirk = true;
 162
 163                dwc3_pdata.tx_de_emphasis_quirk = true;
 164                dwc3_pdata.tx_de_emphasis = 1;
 165
 166                /*
 167                 * FIXME these quirks should be removed when AMD NL
 168                 * taps out
 169                 */
 170                dwc3_pdata.disable_scramble_quirk = true;
 171                dwc3_pdata.dis_u3_susphy_quirk = true;
 172                dwc3_pdata.dis_u2_susphy_quirk = true;
 173        }
 174
 175        ret = platform_device_add_resources(dwc3, res, ARRAY_SIZE(res));
 176        if (ret) {
 177                dev_err(dev, "couldn't add resources to dwc3 device\n");
 178                return ret;
 179        }
 180
 181        pci_set_drvdata(pci, glue);
 182
 183        ret = platform_device_add_data(dwc3, &dwc3_pdata, sizeof(dwc3_pdata));
 184        if (ret)
 185                goto err3;
 186
 187        dma_set_coherent_mask(&dwc3->dev, dev->coherent_dma_mask);
 188
 189        dwc3->dev.dma_mask = dev->dma_mask;
 190        dwc3->dev.dma_parms = dev->dma_parms;
 191        dwc3->dev.parent = dev;
 192        glue->dwc3 = dwc3;
 193
 194        ret = platform_device_add(dwc3);
 195        if (ret) {
 196                dev_err(dev, "failed to register dwc3 device\n");
 197                goto err3;
 198        }
 199
 200        return 0;
 201
 202err3:
 203        platform_device_put(dwc3);
 204        return ret;
 205}
 206
 207static void dwc3_pci_remove(struct pci_dev *pci)
 208{
 209        struct dwc3_pci *glue = pci_get_drvdata(pci);
 210
 211        platform_device_unregister(glue->dwc3);
 212        platform_device_unregister(glue->usb2_phy);
 213        platform_device_unregister(glue->usb3_phy);
 214}
 215
 216static const struct pci_device_id dwc3_pci_id_table[] = {
 217        {
 218                PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS,
 219                                PCI_DEVICE_ID_SYNOPSYS_HAPSUSB3),
 220        },
 221        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BSW), },
 222        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BYT), },
 223        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_MRFLD), },
 224        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTLP), },
 225        { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SPTH), },
 226        { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_NL_USB), },
 227        {  }    /* Terminating Entry */
 228};
 229MODULE_DEVICE_TABLE(pci, dwc3_pci_id_table);
 230
 231#ifdef CONFIG_PM_SLEEP
 232static int dwc3_pci_suspend(struct device *dev)
 233{
 234        struct pci_dev  *pci = to_pci_dev(dev);
 235
 236        pci_disable_device(pci);
 237
 238        return 0;
 239}
 240
 241static int dwc3_pci_resume(struct device *dev)
 242{
 243        struct pci_dev  *pci = to_pci_dev(dev);
 244        int             ret;
 245
 246        ret = pci_enable_device(pci);
 247        if (ret) {
 248                dev_err(dev, "can't re-enable device --> %d\n", ret);
 249                return ret;
 250        }
 251
 252        pci_set_master(pci);
 253
 254        return 0;
 255}
 256#endif /* CONFIG_PM_SLEEP */
 257
 258static const struct dev_pm_ops dwc3_pci_dev_pm_ops = {
 259        SET_SYSTEM_SLEEP_PM_OPS(dwc3_pci_suspend, dwc3_pci_resume)
 260};
 261
 262static struct pci_driver dwc3_pci_driver = {
 263        .name           = "dwc3-pci",
 264        .id_table       = dwc3_pci_id_table,
 265        .probe          = dwc3_pci_probe,
 266        .remove         = dwc3_pci_remove,
 267        .driver         = {
 268                .pm     = &dwc3_pci_dev_pm_ops,
 269        },
 270};
 271
 272MODULE_AUTHOR("Felipe Balbi <balbi@ti.com>");
 273MODULE_LICENSE("GPL v2");
 274MODULE_DESCRIPTION("DesignWare USB3 PCI Glue Layer");
 275
 276module_pci_driver(dwc3_pci_driver);
 277
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.