xref: /kernel/linux/linux-5.10/drivers/usb/dwc2/pci.c (revision 8c2ecf20)
18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * pci.c - DesignWare HS OTG Controller PCI driver
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) 2004-2013 Synopsys, Inc.
68c2ecf20Sopenharmony_ci *
78c2ecf20Sopenharmony_ci * Redistribution and use in source and binary forms, with or without
88c2ecf20Sopenharmony_ci * modification, are permitted provided that the following conditions
98c2ecf20Sopenharmony_ci * are met:
108c2ecf20Sopenharmony_ci * 1. Redistributions of source code must retain the above copyright
118c2ecf20Sopenharmony_ci *    notice, this list of conditions, and the following disclaimer,
128c2ecf20Sopenharmony_ci *    without modification.
138c2ecf20Sopenharmony_ci * 2. Redistributions in binary form must reproduce the above copyright
148c2ecf20Sopenharmony_ci *    notice, this list of conditions and the following disclaimer in the
158c2ecf20Sopenharmony_ci *    documentation and/or other materials provided with the distribution.
168c2ecf20Sopenharmony_ci * 3. The names of the above-listed copyright holders may not be used
178c2ecf20Sopenharmony_ci *    to endorse or promote products derived from this software without
188c2ecf20Sopenharmony_ci *    specific prior written permission.
198c2ecf20Sopenharmony_ci *
208c2ecf20Sopenharmony_ci * ALTERNATIVELY, this software may be distributed under the terms of the
218c2ecf20Sopenharmony_ci * GNU General Public License ("GPL") as published by the Free Software
228c2ecf20Sopenharmony_ci * Foundation; either version 2 of the License, or (at your option) any
238c2ecf20Sopenharmony_ci * later version.
248c2ecf20Sopenharmony_ci *
258c2ecf20Sopenharmony_ci * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
268c2ecf20Sopenharmony_ci * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
278c2ecf20Sopenharmony_ci * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
288c2ecf20Sopenharmony_ci * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
298c2ecf20Sopenharmony_ci * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
308c2ecf20Sopenharmony_ci * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
318c2ecf20Sopenharmony_ci * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
328c2ecf20Sopenharmony_ci * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
338c2ecf20Sopenharmony_ci * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
348c2ecf20Sopenharmony_ci * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
358c2ecf20Sopenharmony_ci * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
368c2ecf20Sopenharmony_ci */
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_ci/*
398c2ecf20Sopenharmony_ci * Provides the initialization and cleanup entry points for the DWC_otg PCI
408c2ecf20Sopenharmony_ci * driver
418c2ecf20Sopenharmony_ci */
428c2ecf20Sopenharmony_ci#include <linux/kernel.h>
438c2ecf20Sopenharmony_ci#include <linux/module.h>
448c2ecf20Sopenharmony_ci#include <linux/moduleparam.h>
458c2ecf20Sopenharmony_ci#include <linux/spinlock.h>
468c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
478c2ecf20Sopenharmony_ci#include <linux/io.h>
488c2ecf20Sopenharmony_ci#include <linux/slab.h>
498c2ecf20Sopenharmony_ci#include <linux/pci.h>
508c2ecf20Sopenharmony_ci#include <linux/usb.h>
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#include <linux/usb/hcd.h>
538c2ecf20Sopenharmony_ci#include <linux/usb/ch11.h>
548c2ecf20Sopenharmony_ci#include <linux/platform_device.h>
558c2ecf20Sopenharmony_ci#include <linux/usb/usb_phy_generic.h>
568c2ecf20Sopenharmony_ci
578c2ecf20Sopenharmony_ci#define PCI_PRODUCT_ID_HAPS_HSOTG	0xabc0
588c2ecf20Sopenharmony_ci
598c2ecf20Sopenharmony_cistatic const char dwc2_driver_name[] = "dwc2-pci";
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_cistruct dwc2_pci_glue {
628c2ecf20Sopenharmony_ci	struct platform_device *dwc2;
638c2ecf20Sopenharmony_ci	struct platform_device *phy;
648c2ecf20Sopenharmony_ci};
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_cistatic int dwc2_pci_quirks(struct pci_dev *pdev, struct platform_device *dwc2)
678c2ecf20Sopenharmony_ci{
688c2ecf20Sopenharmony_ci	if (pdev->vendor == PCI_VENDOR_ID_SYNOPSYS &&
698c2ecf20Sopenharmony_ci	    pdev->device == PCI_PRODUCT_ID_HAPS_HSOTG) {
708c2ecf20Sopenharmony_ci		struct property_entry properties[] = {
718c2ecf20Sopenharmony_ci			{ },
728c2ecf20Sopenharmony_ci		};
738c2ecf20Sopenharmony_ci
748c2ecf20Sopenharmony_ci		return platform_device_add_properties(dwc2, properties);
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	return 0;
788c2ecf20Sopenharmony_ci}
798c2ecf20Sopenharmony_ci
808c2ecf20Sopenharmony_ci/**
818c2ecf20Sopenharmony_ci * dwc2_pci_probe() - Provides the cleanup entry points for the DWC_otg PCI
828c2ecf20Sopenharmony_ci * driver
838c2ecf20Sopenharmony_ci *
848c2ecf20Sopenharmony_ci * @pci: The programming view of DWC_otg PCI
858c2ecf20Sopenharmony_ci */
868c2ecf20Sopenharmony_cistatic void dwc2_pci_remove(struct pci_dev *pci)
878c2ecf20Sopenharmony_ci{
888c2ecf20Sopenharmony_ci	struct dwc2_pci_glue *glue = pci_get_drvdata(pci);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	platform_device_unregister(glue->dwc2);
918c2ecf20Sopenharmony_ci	usb_phy_generic_unregister(glue->phy);
928c2ecf20Sopenharmony_ci	pci_set_drvdata(pci, NULL);
938c2ecf20Sopenharmony_ci}
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_cistatic int dwc2_pci_probe(struct pci_dev *pci,
968c2ecf20Sopenharmony_ci			  const struct pci_device_id *id)
978c2ecf20Sopenharmony_ci{
988c2ecf20Sopenharmony_ci	struct resource		res[2];
998c2ecf20Sopenharmony_ci	struct platform_device	*dwc2;
1008c2ecf20Sopenharmony_ci	struct platform_device	*phy;
1018c2ecf20Sopenharmony_ci	int			ret;
1028c2ecf20Sopenharmony_ci	struct device		*dev = &pci->dev;
1038c2ecf20Sopenharmony_ci	struct dwc2_pci_glue	*glue;
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci	ret = pcim_enable_device(pci);
1068c2ecf20Sopenharmony_ci	if (ret) {
1078c2ecf20Sopenharmony_ci		dev_err(dev, "failed to enable pci device\n");
1088c2ecf20Sopenharmony_ci		return -ENODEV;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	pci_set_master(pci);
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	phy = usb_phy_generic_register();
1148c2ecf20Sopenharmony_ci	if (IS_ERR(phy)) {
1158c2ecf20Sopenharmony_ci		dev_err(dev, "error registering generic PHY (%ld)\n",
1168c2ecf20Sopenharmony_ci			PTR_ERR(phy));
1178c2ecf20Sopenharmony_ci		return PTR_ERR(phy);
1188c2ecf20Sopenharmony_ci	}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	dwc2 = platform_device_alloc("dwc2", PLATFORM_DEVID_AUTO);
1218c2ecf20Sopenharmony_ci	if (!dwc2) {
1228c2ecf20Sopenharmony_ci		dev_err(dev, "couldn't allocate dwc2 device\n");
1238c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1248c2ecf20Sopenharmony_ci		goto err;
1258c2ecf20Sopenharmony_ci	}
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci	memset(res, 0x00, sizeof(struct resource) * ARRAY_SIZE(res));
1288c2ecf20Sopenharmony_ci
1298c2ecf20Sopenharmony_ci	res[0].start	= pci_resource_start(pci, 0);
1308c2ecf20Sopenharmony_ci	res[0].end	= pci_resource_end(pci, 0);
1318c2ecf20Sopenharmony_ci	res[0].name	= "dwc2";
1328c2ecf20Sopenharmony_ci	res[0].flags	= IORESOURCE_MEM;
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci	res[1].start	= pci->irq;
1358c2ecf20Sopenharmony_ci	res[1].name	= "dwc2";
1368c2ecf20Sopenharmony_ci	res[1].flags	= IORESOURCE_IRQ;
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci	ret = platform_device_add_resources(dwc2, res, ARRAY_SIZE(res));
1398c2ecf20Sopenharmony_ci	if (ret) {
1408c2ecf20Sopenharmony_ci		dev_err(dev, "couldn't add resources to dwc2 device\n");
1418c2ecf20Sopenharmony_ci		goto err;
1428c2ecf20Sopenharmony_ci	}
1438c2ecf20Sopenharmony_ci
1448c2ecf20Sopenharmony_ci	dwc2->dev.parent = dev;
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci	ret = dwc2_pci_quirks(pci, dwc2);
1478c2ecf20Sopenharmony_ci	if (ret)
1488c2ecf20Sopenharmony_ci		goto err;
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_ci	glue = devm_kzalloc(dev, sizeof(*glue), GFP_KERNEL);
1518c2ecf20Sopenharmony_ci	if (!glue) {
1528c2ecf20Sopenharmony_ci		ret = -ENOMEM;
1538c2ecf20Sopenharmony_ci		goto err;
1548c2ecf20Sopenharmony_ci	}
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	ret = platform_device_add(dwc2);
1578c2ecf20Sopenharmony_ci	if (ret) {
1588c2ecf20Sopenharmony_ci		dev_err(dev, "failed to register dwc2 device\n");
1598c2ecf20Sopenharmony_ci		goto err;
1608c2ecf20Sopenharmony_ci	}
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	glue->phy = phy;
1638c2ecf20Sopenharmony_ci	glue->dwc2 = dwc2;
1648c2ecf20Sopenharmony_ci	pci_set_drvdata(pci, glue);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	return 0;
1678c2ecf20Sopenharmony_cierr:
1688c2ecf20Sopenharmony_ci	usb_phy_generic_unregister(phy);
1698c2ecf20Sopenharmony_ci	platform_device_put(dwc2);
1708c2ecf20Sopenharmony_ci	return ret;
1718c2ecf20Sopenharmony_ci}
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic const struct pci_device_id dwc2_pci_ids[] = {
1748c2ecf20Sopenharmony_ci	{
1758c2ecf20Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_SYNOPSYS, PCI_PRODUCT_ID_HAPS_HSOTG),
1768c2ecf20Sopenharmony_ci	},
1778c2ecf20Sopenharmony_ci	{
1788c2ecf20Sopenharmony_ci		PCI_DEVICE(PCI_VENDOR_ID_STMICRO,
1798c2ecf20Sopenharmony_ci			   PCI_DEVICE_ID_STMICRO_USB_OTG),
1808c2ecf20Sopenharmony_ci	},
1818c2ecf20Sopenharmony_ci	{ /* end: all zeroes */ }
1828c2ecf20Sopenharmony_ci};
1838c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(pci, dwc2_pci_ids);
1848c2ecf20Sopenharmony_ci
1858c2ecf20Sopenharmony_cistatic struct pci_driver dwc2_pci_driver = {
1868c2ecf20Sopenharmony_ci	.name = dwc2_driver_name,
1878c2ecf20Sopenharmony_ci	.id_table = dwc2_pci_ids,
1888c2ecf20Sopenharmony_ci	.probe = dwc2_pci_probe,
1898c2ecf20Sopenharmony_ci	.remove = dwc2_pci_remove,
1908c2ecf20Sopenharmony_ci};
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_cimodule_pci_driver(dwc2_pci_driver);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("DESIGNWARE HS OTG PCI Bus Glue");
1958c2ecf20Sopenharmony_ciMODULE_AUTHOR("Synopsys, Inc.");
1968c2ecf20Sopenharmony_ciMODULE_LICENSE("Dual BSD/GPL");
197