Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * ci_hdrc_pci.c - MIPS USB IP core family device controller
0004  *
0005  * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved.
0006  *
0007  * Author: David Lopo
0008  */
0009 
0010 #include <linux/platform_device.h>
0011 #include <linux/module.h>
0012 #include <linux/pci.h>
0013 #include <linux/interrupt.h>
0014 #include <linux/usb/gadget.h>
0015 #include <linux/usb/chipidea.h>
0016 #include <linux/usb/usb_phy_generic.h>
0017 
0018 /* driver name */
0019 #define UDC_DRIVER_NAME   "ci_hdrc_pci"
0020 
0021 struct ci_hdrc_pci {
0022     struct platform_device  *ci;
0023     struct platform_device  *phy;
0024 };
0025 
0026 /******************************************************************************
0027  * PCI block
0028  *****************************************************************************/
0029 static struct ci_hdrc_platform_data pci_platdata = {
0030     .name       = UDC_DRIVER_NAME,
0031     .capoffset  = DEF_CAPOFFSET,
0032 };
0033 
0034 static struct ci_hdrc_platform_data langwell_pci_platdata = {
0035     .name       = UDC_DRIVER_NAME,
0036     .capoffset  = 0,
0037 };
0038 
0039 static struct ci_hdrc_platform_data penwell_pci_platdata = {
0040     .name       = UDC_DRIVER_NAME,
0041     .capoffset  = 0,
0042     .power_budget   = 200,
0043 };
0044 
0045 /**
0046  * ci_hdrc_pci_probe: PCI probe
0047  * @pdev: USB device controller being probed
0048  * @id:   PCI hotplug ID connecting controller to UDC framework
0049  *
0050  * This function returns an error code
0051  * Allocates basic PCI resources for this USB device controller, and then
0052  * invokes the udc_probe() method to start the UDC associated with it
0053  */
0054 static int ci_hdrc_pci_probe(struct pci_dev *pdev,
0055                        const struct pci_device_id *id)
0056 {
0057     struct ci_hdrc_platform_data *platdata = (void *)id->driver_data;
0058     struct ci_hdrc_pci *ci;
0059     struct resource res[3];
0060     int retval = 0, nres = 2;
0061 
0062     if (!platdata) {
0063         dev_err(&pdev->dev, "device doesn't provide driver data\n");
0064         return -ENODEV;
0065     }
0066 
0067     ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL);
0068     if (!ci)
0069         return -ENOMEM;
0070 
0071     retval = pcim_enable_device(pdev);
0072     if (retval)
0073         return retval;
0074 
0075     if (!pdev->irq) {
0076         dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!");
0077         return -ENODEV;
0078     }
0079 
0080     pci_set_master(pdev);
0081     pci_try_set_mwi(pdev);
0082 
0083     /* register a nop PHY */
0084     ci->phy = usb_phy_generic_register();
0085     if (IS_ERR(ci->phy))
0086         return PTR_ERR(ci->phy);
0087 
0088     memset(res, 0, sizeof(res));
0089     res[0].start    = pci_resource_start(pdev, 0);
0090     res[0].end  = pci_resource_end(pdev, 0);
0091     res[0].flags    = IORESOURCE_MEM;
0092     res[1].start    = pdev->irq;
0093     res[1].flags    = IORESOURCE_IRQ;
0094 
0095     ci->ci = ci_hdrc_add_device(&pdev->dev, res, nres, platdata);
0096     if (IS_ERR(ci->ci)) {
0097         dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n");
0098         usb_phy_generic_unregister(ci->phy);
0099         return PTR_ERR(ci->ci);
0100     }
0101 
0102     pci_set_drvdata(pdev, ci);
0103 
0104     return 0;
0105 }
0106 
0107 /**
0108  * ci_hdrc_pci_remove: PCI remove
0109  * @pdev: USB Device Controller being removed
0110  *
0111  * Reverses the effect of ci_hdrc_pci_probe(),
0112  * first invoking the udc_remove() and then releases
0113  * all PCI resources allocated for this USB device controller
0114  */
0115 static void ci_hdrc_pci_remove(struct pci_dev *pdev)
0116 {
0117     struct ci_hdrc_pci *ci = pci_get_drvdata(pdev);
0118 
0119     ci_hdrc_remove_device(ci->ci);
0120     usb_phy_generic_unregister(ci->phy);
0121 }
0122 
0123 /*
0124  * PCI device table
0125  * PCI device structure
0126  *
0127  * Check "pci.h" for details
0128  *
0129  * Note: ehci-pci driver may try to probe the device first. You have to add an
0130  * ID to the bypass_pci_id_table in ehci-pci driver to prevent this.
0131  */
0132 static const struct pci_device_id ci_hdrc_pci_id_table[] = {
0133     {
0134         PCI_DEVICE(0x153F, 0x1004),
0135         .driver_data = (kernel_ulong_t)&pci_platdata,
0136     },
0137     {
0138         PCI_DEVICE(0x153F, 0x1006),
0139         .driver_data = (kernel_ulong_t)&pci_platdata,
0140     },
0141     {
0142         PCI_VDEVICE(INTEL, 0x0811),
0143         .driver_data = (kernel_ulong_t)&langwell_pci_platdata,
0144     },
0145     {
0146         PCI_VDEVICE(INTEL, 0x0829),
0147         .driver_data = (kernel_ulong_t)&penwell_pci_platdata,
0148     },
0149     {
0150         /* Intel Clovertrail */
0151         PCI_VDEVICE(INTEL, 0xe006),
0152         .driver_data = (kernel_ulong_t)&penwell_pci_platdata,
0153     },
0154     { 0 } /* end: all zeroes */
0155 };
0156 MODULE_DEVICE_TABLE(pci, ci_hdrc_pci_id_table);
0157 
0158 static struct pci_driver ci_hdrc_pci_driver = {
0159     .name         = UDC_DRIVER_NAME,
0160     .id_table     = ci_hdrc_pci_id_table,
0161     .probe        = ci_hdrc_pci_probe,
0162     .remove       = ci_hdrc_pci_remove,
0163 };
0164 
0165 module_pci_driver(ci_hdrc_pci_driver);
0166 
0167 MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>");
0168 MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller");
0169 MODULE_LICENSE("GPL");
0170 MODULE_ALIAS("platform:ci13xxx_pci");