1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * ci_hdrc_pci.c - MIPS USB IP core family device controller 4 * 5 * Copyright (C) 2008 Chipidea - MIPS Technologies, Inc. All rights reserved. 6 * 7 * Author: David Lopo 8 */ 9 10 #include <linux/platform_device.h> 11 #include <linux/module.h> 12 #include <linux/pci.h> 13 #include <linux/interrupt.h> 14 #include <linux/usb/gadget.h> 15 #include <linux/usb/chipidea.h> 16 #include <linux/usb/usb_phy_generic.h> 17 18 /* driver name */ 19 #define UDC_DRIVER_NAME "ci_hdrc_pci" 20 21 struct ci_hdrc_pci { 22 struct platform_device *ci; 23 struct platform_device *phy; 24 }; 25 26 /****************************************************************************** 27 * PCI block 28 *****************************************************************************/ 29 static struct ci_hdrc_platform_data pci_platdata = { 30 .name = UDC_DRIVER_NAME, 31 .capoffset = DEF_CAPOFFSET, 32 }; 33 34 static struct ci_hdrc_platform_data langwell_pci_platdata = { 35 .name = UDC_DRIVER_NAME, 36 .capoffset = 0, 37 }; 38 39 static struct ci_hdrc_platform_data penwell_pci_platdata = { 40 .name = UDC_DRIVER_NAME, 41 .capoffset = 0, 42 .power_budget = 200, 43 }; 44 45 /** 46 * ci_hdrc_pci_probe: PCI probe 47 * @pdev: USB device controller being probed 48 * @id: PCI hotplug ID connecting controller to UDC framework 49 * 50 * This function returns an error code 51 * Allocates basic PCI resources for this USB device controller, and then 52 * invokes the udc_probe() method to start the UDC associated with it 53 */ 54 static int ci_hdrc_pci_probe(struct pci_dev *pdev, 55 const struct pci_device_id *id) 56 { 57 struct ci_hdrc_platform_data *platdata = (void *)id->driver_data; 58 struct ci_hdrc_pci *ci; 59 struct resource res[3]; 60 int retval = 0, nres = 2; 61 62 if (!platdata) { 63 dev_err(&pdev->dev, "device doesn't provide driver data\n"); 64 return -ENODEV; 65 } 66 67 ci = devm_kzalloc(&pdev->dev, sizeof(*ci), GFP_KERNEL); 68 if (!ci) 69 return -ENOMEM; 70 71 retval = pcim_enable_device(pdev); 72 if (retval) 73 return retval; 74 75 if (!pdev->irq) { 76 dev_err(&pdev->dev, "No IRQ, check BIOS/PCI setup!"); 77 return -ENODEV; 78 } 79 80 pci_set_master(pdev); 81 pci_try_set_mwi(pdev); 82 83 /* register a nop PHY */ 84 ci->phy = usb_phy_generic_register(); 85 if (IS_ERR(ci->phy)) 86 return PTR_ERR(ci->phy); 87 88 memset(res, 0, sizeof(res)); 89 res[0].start = pci_resource_start(pdev, 0); 90 res[0].end = pci_resource_end(pdev, 0); 91 res[0].flags = IORESOURCE_MEM; 92 res[1].start = pdev->irq; 93 res[1].flags = IORESOURCE_IRQ; 94 95 ci->ci = ci_hdrc_add_device(&pdev->dev, res, nres, platdata); 96 if (IS_ERR(ci->ci)) { 97 dev_err(&pdev->dev, "ci_hdrc_add_device failed!\n"); 98 usb_phy_generic_unregister(ci->phy); 99 return PTR_ERR(ci->ci); 100 } 101 102 pci_set_drvdata(pdev, ci); 103 104 return 0; 105 } 106 107 /** 108 * ci_hdrc_pci_remove: PCI remove 109 * @pdev: USB Device Controller being removed 110 * 111 * Reverses the effect of ci_hdrc_pci_probe(), 112 * first invoking the udc_remove() and then releases 113 * all PCI resources allocated for this USB device controller 114 */ 115 static void ci_hdrc_pci_remove(struct pci_dev *pdev) 116 { 117 struct ci_hdrc_pci *ci = pci_get_drvdata(pdev); 118 119 ci_hdrc_remove_device(ci->ci); 120 usb_phy_generic_unregister(ci->phy); 121 } 122 123 /** 124 * PCI device table 125 * PCI device structure 126 * 127 * Check "pci.h" for details 128 * 129 * Note: ehci-pci driver may try to probe the device first. You have to add an 130 * ID to the bypass_pci_id_table in ehci-pci driver to prevent this. 131 */ 132 static const struct pci_device_id ci_hdrc_pci_id_table[] = { 133 { 134 PCI_DEVICE(0x153F, 0x1004), 135 .driver_data = (kernel_ulong_t)&pci_platdata, 136 }, 137 { 138 PCI_DEVICE(0x153F, 0x1006), 139 .driver_data = (kernel_ulong_t)&pci_platdata, 140 }, 141 { 142 PCI_VDEVICE(INTEL, 0x0811), 143 .driver_data = (kernel_ulong_t)&langwell_pci_platdata, 144 }, 145 { 146 PCI_VDEVICE(INTEL, 0x0829), 147 .driver_data = (kernel_ulong_t)&penwell_pci_platdata, 148 }, 149 { 150 /* Intel Clovertrail */ 151 PCI_VDEVICE(INTEL, 0xe006), 152 .driver_data = (kernel_ulong_t)&penwell_pci_platdata, 153 }, 154 { 0 } /* end: all zeroes */ 155 }; 156 MODULE_DEVICE_TABLE(pci, ci_hdrc_pci_id_table); 157 158 static struct pci_driver ci_hdrc_pci_driver = { 159 .name = UDC_DRIVER_NAME, 160 .id_table = ci_hdrc_pci_id_table, 161 .probe = ci_hdrc_pci_probe, 162 .remove = ci_hdrc_pci_remove, 163 }; 164 165 module_pci_driver(ci_hdrc_pci_driver); 166 167 MODULE_AUTHOR("MIPS - David Lopo <dlopo@chipidea.mips.com>"); 168 MODULE_DESCRIPTION("MIPS CI13XXX USB Peripheral Controller"); 169 MODULE_LICENSE("GPL"); 170 MODULE_ALIAS("platform:ci13xxx_pci"); 171