162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause) 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * pci.c - DesignWare HS OTG Controller PCI driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (C) 2004-2013 Synopsys, Inc. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci/* 962306a36Sopenharmony_ci * Provides the initialization and cleanup entry points for the DWC_otg PCI 1062306a36Sopenharmony_ci * driver 1162306a36Sopenharmony_ci */ 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/moduleparam.h> 1562306a36Sopenharmony_ci#include <linux/spinlock.h> 1662306a36Sopenharmony_ci#include <linux/interrupt.h> 1762306a36Sopenharmony_ci#include <linux/io.h> 1862306a36Sopenharmony_ci#include <linux/slab.h> 1962306a36Sopenharmony_ci#include <linux/pci.h> 2062306a36Sopenharmony_ci#include <linux/usb.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <linux/usb/hcd.h> 2362306a36Sopenharmony_ci#include <linux/usb/ch11.h> 2462306a36Sopenharmony_ci#include <linux/platform_device.h> 2562306a36Sopenharmony_ci#include <linux/usb/usb_phy_generic.h> 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci#include "core.h" 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cistatic const char dwc2_driver_name[] = "dwc2-pci"; 3062306a36Sopenharmony_ci 3162306a36Sopenharmony_cistruct dwc2_pci_glue { 3262306a36Sopenharmony_ci struct platform_device *dwc2; 3362306a36Sopenharmony_ci struct platform_device *phy; 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/** 3762306a36Sopenharmony_ci * dwc2_pci_remove() - Provides the cleanup entry points for the DWC_otg PCI 3862306a36Sopenharmony_ci * driver 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * @pci: The programming view of DWC_otg PCI 4162306a36Sopenharmony_ci */ 4262306a36Sopenharmony_cistatic void dwc2_pci_remove(struct pci_dev *pci) 4362306a36Sopenharmony_ci{ 4462306a36Sopenharmony_ci struct dwc2_pci_glue *glue = pci_get_drvdata(pci); 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci platform_device_unregister(glue->dwc2); 4762306a36Sopenharmony_ci usb_phy_generic_unregister(glue->phy); 4862306a36Sopenharmony_ci pci_set_drvdata(pci, NULL); 4962306a36Sopenharmony_ci} 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistatic int dwc2_pci_probe(struct pci_dev *pci, 5262306a36Sopenharmony_ci const struct pci_device_id *id) 5362306a36Sopenharmony_ci{ 5462306a36Sopenharmony_ci struct resource res[2]; 5562306a36Sopenharmony_ci struct platform_device *dwc2; 5662306a36Sopenharmony_ci struct platform_device *phy; 5762306a36Sopenharmony_ci int ret; 5862306a36Sopenharmony_ci struct device *dev = &pci->dev; 5962306a36Sopenharmony_ci struct dwc2_pci_glue *glue; 6062306a36Sopenharmony_ci 6162306a36Sopenharmony_ci ret = pcim_enable_device(pci); 6262306a36Sopenharmony_ci if (ret) { 6362306a36Sopenharmony_ci dev_err(dev, "failed to enable pci device\n"); 6462306a36Sopenharmony_ci return -ENODEV; 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci pci_set_master(pci); 6862306a36Sopenharmony_ci 6962306a36Sopenharmony_ci phy = usb_phy_generic_register(); 7062306a36Sopenharmony_ci if (IS_ERR(phy)) { 7162306a36Sopenharmony_ci dev_err(dev, "error registering generic PHY (%ld)\n", 7262306a36Sopenharmony_ci PTR_ERR(phy)); 7362306a36Sopenharmony_ci return PTR_ERR(phy); 7462306a36Sopenharmony_ci } 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci dwc2 = platform_device_alloc("dwc2", PLATFORM_DEVID_AUTO); 7762306a36Sopenharmony_ci if (!dwc2) { 7862306a36Sopenharmony_ci dev_err(dev, "couldn't allocate dwc2 device\n"); 7962306a36Sopenharmony_ci ret = -ENOMEM; 8062306a36Sopenharmony_ci goto err; 8162306a36Sopenharmony_ci } 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res)); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci res[0].start = pci_resource_start(pci, 0); 8662306a36Sopenharmony_ci res[0].end = pci_resource_end(pci, 0); 8762306a36Sopenharmony_ci res[0].name = "dwc2"; 8862306a36Sopenharmony_ci res[0].flags = IORESOURCE_MEM; 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_ci res[1].start = pci->irq; 9162306a36Sopenharmony_ci res[1].name = "dwc2"; 9262306a36Sopenharmony_ci res[1].flags = IORESOURCE_IRQ; 9362306a36Sopenharmony_ci 9462306a36Sopenharmony_ci ret = platform_device_add_resources(dwc2, res, ARRAY_SIZE(res)); 9562306a36Sopenharmony_ci if (ret) { 9662306a36Sopenharmony_ci dev_err(dev, "couldn't add resources to dwc2 device\n"); 9762306a36Sopenharmony_ci goto err; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci dwc2->dev.parent = dev; 10162306a36Sopenharmony_ci 10262306a36Sopenharmony_ci glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL); 10362306a36Sopenharmony_ci if (!glue) { 10462306a36Sopenharmony_ci ret = -ENOMEM; 10562306a36Sopenharmony_ci goto err; 10662306a36Sopenharmony_ci } 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci ret = platform_device_add(dwc2); 10962306a36Sopenharmony_ci if (ret) { 11062306a36Sopenharmony_ci dev_err(dev, "failed to register dwc2 device\n"); 11162306a36Sopenharmony_ci goto err; 11262306a36Sopenharmony_ci } 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci glue->phy = phy; 11562306a36Sopenharmony_ci glue->dwc2 = dwc2; 11662306a36Sopenharmony_ci pci_set_drvdata(pci, glue); 11762306a36Sopenharmony_ci 11862306a36Sopenharmony_ci return 0; 11962306a36Sopenharmony_cierr: 12062306a36Sopenharmony_ci usb_phy_generic_unregister(phy); 12162306a36Sopenharmony_ci platform_device_put(dwc2); 12262306a36Sopenharmony_ci return ret; 12362306a36Sopenharmony_ci} 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_cistatic struct pci_driver dwc2_pci_driver = { 12662306a36Sopenharmony_ci .name = dwc2_driver_name, 12762306a36Sopenharmony_ci .id_table = dwc2_pci_ids, 12862306a36Sopenharmony_ci .probe = dwc2_pci_probe, 12962306a36Sopenharmony_ci .remove = dwc2_pci_remove, 13062306a36Sopenharmony_ci}; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_cimodule_pci_driver(dwc2_pci_driver); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ciMODULE_DESCRIPTION("DESIGNWARE HS OTG PCI Bus Glue"); 13562306a36Sopenharmony_ciMODULE_AUTHOR("Synopsys, Inc."); 13662306a36Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL"); 137