root/drivers/usb/cdns3/cdns3-pci-wrap.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. cdns3_get_second_fun
  2. cdns3_pci_probe
  3. cdns3_pci_remove

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Cadence USBSS PCI Glue driver
   4  *
   5  * Copyright (C) 2018-2019 Cadence.
   6  *
   7  * Author: Pawel Laszczak <pawell@cadence.com>
   8  */
   9 
  10 #include <linux/kernel.h>
  11 #include <linux/module.h>
  12 #include <linux/pci.h>
  13 #include <linux/platform_device.h>
  14 #include <linux/dma-mapping.h>
  15 #include <linux/slab.h>
  16 
  17 struct cdns3_wrap {
  18         struct platform_device *plat_dev;
  19         struct resource dev_res[6];
  20         int devfn;
  21 };
  22 
  23 #define RES_IRQ_HOST_ID         0
  24 #define RES_IRQ_PERIPHERAL_ID   1
  25 #define RES_IRQ_OTG_ID          2
  26 #define RES_HOST_ID             3
  27 #define RES_DEV_ID              4
  28 #define RES_DRD_ID              5
  29 
  30 #define PCI_BAR_HOST            0
  31 #define PCI_BAR_DEV             2
  32 #define PCI_BAR_OTG             0
  33 
  34 #define PCI_DEV_FN_HOST_DEVICE  0
  35 #define PCI_DEV_FN_OTG          1
  36 
  37 #define PCI_DRIVER_NAME         "cdns3-pci-usbss"
  38 #define PLAT_DRIVER_NAME        "cdns-usb3"
  39 
  40 #define CDNS_VENDOR_ID          0x17cd
  41 #define CDNS_DEVICE_ID          0x0100
  42 
  43 static struct pci_dev *cdns3_get_second_fun(struct pci_dev *pdev)
  44 {
  45         struct pci_dev *func;
  46 
  47         /*
  48          * Gets the second function.
  49          * It's little tricky, but this platform has two function.
  50          * The fist keeps resources for Host/Device while the second
  51          * keeps resources for DRD/OTG.
  52          */
  53         func = pci_get_device(pdev->vendor, pdev->device, NULL);
  54         if (unlikely(!func))
  55                 return NULL;
  56 
  57         if (func->devfn == pdev->devfn) {
  58                 func = pci_get_device(pdev->vendor, pdev->device, func);
  59                 if (unlikely(!func))
  60                         return NULL;
  61         }
  62 
  63         return func;
  64 }
  65 
  66 static int cdns3_pci_probe(struct pci_dev *pdev,
  67                            const struct pci_device_id *id)
  68 {
  69         struct platform_device_info plat_info;
  70         struct cdns3_wrap *wrap;
  71         struct resource *res;
  72         struct pci_dev *func;
  73         int err;
  74 
  75         /*
  76          * for GADGET/HOST PCI (devfn) function number is 0,
  77          * for OTG PCI (devfn) function number is 1
  78          */
  79         if (!id || (pdev->devfn != PCI_DEV_FN_HOST_DEVICE &&
  80                     pdev->devfn != PCI_DEV_FN_OTG))
  81                 return -EINVAL;
  82 
  83         func = cdns3_get_second_fun(pdev);
  84         if (unlikely(!func))
  85                 return -EINVAL;
  86 
  87         err = pcim_enable_device(pdev);
  88         if (err) {
  89                 dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", err);
  90                 return err;
  91         }
  92 
  93         pci_set_master(pdev);
  94 
  95         if (pci_is_enabled(func)) {
  96                 wrap = pci_get_drvdata(func);
  97         } else {
  98                 wrap = kzalloc(sizeof(*wrap), GFP_KERNEL);
  99                 if (!wrap) {
 100                         pci_disable_device(pdev);
 101                         return -ENOMEM;
 102                 }
 103         }
 104 
 105         res = wrap->dev_res;
 106 
 107         if (pdev->devfn == PCI_DEV_FN_HOST_DEVICE) {
 108                 /* function 0: host(BAR_0) + device(BAR_1).*/
 109                 dev_dbg(&pdev->dev, "Initialize Device resources\n");
 110                 res[RES_DEV_ID].start = pci_resource_start(pdev, PCI_BAR_DEV);
 111                 res[RES_DEV_ID].end =   pci_resource_end(pdev, PCI_BAR_DEV);
 112                 res[RES_DEV_ID].name = "dev";
 113                 res[RES_DEV_ID].flags = IORESOURCE_MEM;
 114                 dev_dbg(&pdev->dev, "USBSS-DEV physical base addr: %pa\n",
 115                         &res[RES_DEV_ID].start);
 116 
 117                 res[RES_HOST_ID].start = pci_resource_start(pdev, PCI_BAR_HOST);
 118                 res[RES_HOST_ID].end = pci_resource_end(pdev, PCI_BAR_HOST);
 119                 res[RES_HOST_ID].name = "xhci";
 120                 res[RES_HOST_ID].flags = IORESOURCE_MEM;
 121                 dev_dbg(&pdev->dev, "USBSS-XHCI physical base addr: %pa\n",
 122                         &res[RES_HOST_ID].start);
 123 
 124                 /* Interrupt for XHCI */
 125                 wrap->dev_res[RES_IRQ_HOST_ID].start = pdev->irq;
 126                 wrap->dev_res[RES_IRQ_HOST_ID].name = "host";
 127                 wrap->dev_res[RES_IRQ_HOST_ID].flags = IORESOURCE_IRQ;
 128 
 129                 /* Interrupt device. It's the same as for HOST. */
 130                 wrap->dev_res[RES_IRQ_PERIPHERAL_ID].start = pdev->irq;
 131                 wrap->dev_res[RES_IRQ_PERIPHERAL_ID].name = "peripheral";
 132                 wrap->dev_res[RES_IRQ_PERIPHERAL_ID].flags = IORESOURCE_IRQ;
 133         } else {
 134                 res[RES_DRD_ID].start = pci_resource_start(pdev, PCI_BAR_OTG);
 135                 res[RES_DRD_ID].end =   pci_resource_end(pdev, PCI_BAR_OTG);
 136                 res[RES_DRD_ID].name = "otg";
 137                 res[RES_DRD_ID].flags = IORESOURCE_MEM;
 138                 dev_dbg(&pdev->dev, "USBSS-DRD physical base addr: %pa\n",
 139                         &res[RES_DRD_ID].start);
 140 
 141                 /* Interrupt for OTG/DRD. */
 142                 wrap->dev_res[RES_IRQ_OTG_ID].start = pdev->irq;
 143                 wrap->dev_res[RES_IRQ_OTG_ID].name = "otg";
 144                 wrap->dev_res[RES_IRQ_OTG_ID].flags = IORESOURCE_IRQ;
 145         }
 146 
 147         if (pci_is_enabled(func)) {
 148                 /* set up platform device info */
 149                 memset(&plat_info, 0, sizeof(plat_info));
 150                 plat_info.parent = &pdev->dev;
 151                 plat_info.fwnode = pdev->dev.fwnode;
 152                 plat_info.name = PLAT_DRIVER_NAME;
 153                 plat_info.id = pdev->devfn;
 154                 wrap->devfn  = pdev->devfn;
 155                 plat_info.res = wrap->dev_res;
 156                 plat_info.num_res = ARRAY_SIZE(wrap->dev_res);
 157                 plat_info.dma_mask = pdev->dma_mask;
 158                 /* register platform device */
 159                 wrap->plat_dev = platform_device_register_full(&plat_info);
 160                 if (IS_ERR(wrap->plat_dev)) {
 161                         pci_disable_device(pdev);
 162                         err = PTR_ERR(wrap->plat_dev);
 163                         kfree(wrap);
 164                         return err;
 165                 }
 166         }
 167 
 168         pci_set_drvdata(pdev, wrap);
 169         return err;
 170 }
 171 
 172 static void cdns3_pci_remove(struct pci_dev *pdev)
 173 {
 174         struct cdns3_wrap *wrap;
 175         struct pci_dev *func;
 176 
 177         func = cdns3_get_second_fun(pdev);
 178 
 179         wrap = (struct cdns3_wrap *)pci_get_drvdata(pdev);
 180         if (wrap->devfn == pdev->devfn)
 181                 platform_device_unregister(wrap->plat_dev);
 182 
 183         if (!pci_is_enabled(func))
 184                 kfree(wrap);
 185 }
 186 
 187 static const struct pci_device_id cdns3_pci_ids[] = {
 188         { PCI_DEVICE(CDNS_VENDOR_ID, CDNS_DEVICE_ID), },
 189         { 0, }
 190 };
 191 
 192 static struct pci_driver cdns3_pci_driver = {
 193         .name = PCI_DRIVER_NAME,
 194         .id_table = cdns3_pci_ids,
 195         .probe = cdns3_pci_probe,
 196         .remove = cdns3_pci_remove,
 197 };
 198 
 199 module_pci_driver(cdns3_pci_driver);
 200 MODULE_DEVICE_TABLE(pci, cdns3_pci_ids);
 201 
 202 MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
 203 MODULE_LICENSE("GPL v2");
 204 MODULE_DESCRIPTION("Cadence USBSS PCI wrapperr");

/* [<][>][^][v][top][bottom][index][help] */