Commit 3eb1f1ef authored by Pawel Laszczak's avatar Pawel Laszczak Committed by Greg Kroah-Hartman

usb: cdns2: Add main part of Cadence USBHS driver

This patch introduces the main part of Cadence USBHS driver
to Linux kernel.
To reduce the patch size a little bit, the header file gadget.h was
intentionally added as separate patch.

The Cadence USB 2.0 Controller is a highly configurable IP Core which
supports both full and high speed data transfer.

The current driver has been validated with FPGA platform. We have
support for PCIe bus, which is used on FPGA prototyping.
Signed-off-by: default avatarPawel Laszczak <pawell@cadence.com>
Message-ID: <20230602102644.77470-3-pawell@cadence.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 0ca2026e
......@@ -463,6 +463,8 @@ config USB_ASPEED_UDC
source "drivers/usb/gadget/udc/aspeed-vhub/Kconfig"
source "drivers/usb/gadget/udc/cdns2/Kconfig"
#
# LAST -- dummy/emulated controller
#
......
......@@ -42,3 +42,4 @@ obj-$(CONFIG_USB_ASPEED_VHUB) += aspeed-vhub/
obj-$(CONFIG_USB_ASPEED_UDC) += aspeed_udc.o
obj-$(CONFIG_USB_BDC_UDC) += bdc/
obj-$(CONFIG_USB_MAX3420_UDC) += max3420_udc.o
obj-$(CONFIG_USB_CDNS2_UDC) += cdns2/
config USB_CDNS2_UDC
tristate "Cadence USBHS Device Controller"
depends on USB_PCI && ACPI && HAS_DMA
help
Cadence USBHS Device controller is a PCI based USB peripheral
controller which supports both full and high speed USB 2.0
data transfers.
Say "y" to link the driver statically, or "m" to build a
dynamically linked module called "cdns2-udc-pci.ko" and to
force all gadget drivers to also be dynamically linked.
# SPDX-License-Identifier: GPL-2.0
# define_trace.h needs to know how to find our header
obj-$(CONFIG_USB_CDNS2_UDC) += cdns2-udc-pci.o
cdns2-udc-pci-$(CONFIG_USB_CDNS2_UDC) += cdns2-pci.o cdns2-gadget.o cdns2-ep0.o
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0
/*
* Cadence USBHS-DEV controller - PCI Glue driver.
*
* Copyright (C) 2023 Cadence.
*
* Author: Pawel Laszczak <pawell@cadence.com>
*
*/
#include <linux/pm_runtime.h>
#include <linux/slab.h>
#include <linux/pci.h>
#include "cdns2-gadget.h"
#define PCI_DRIVER_NAME "cdns-pci-usbhs"
#define CDNS_VENDOR_ID 0x17cd
#define CDNS_DEVICE_ID 0x0120
#define PCI_BAR_DEV 0
#define PCI_DEV_FN_DEVICE 0
static int cdns2_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
resource_size_t rsrc_start, rsrc_len;
struct device *dev = &pdev->dev;
struct cdns2_device *priv_dev;
struct resource *res;
int ret;
/* For GADGET PCI (devfn) function number is 0. */
if (!id || pdev->devfn != PCI_DEV_FN_DEVICE ||
pdev->class != PCI_CLASS_SERIAL_USB_DEVICE)
return -EINVAL;
ret = pcim_enable_device(pdev);
if (ret) {
dev_err(&pdev->dev, "Enabling PCI device has failed %d\n", ret);
return ret;
}
pci_set_master(pdev);
priv_dev = devm_kzalloc(&pdev->dev, sizeof(*priv_dev), GFP_KERNEL);
if (!priv_dev)
return -ENOMEM;
dev_dbg(dev, "Initialize resources\n");
rsrc_start = pci_resource_start(pdev, PCI_BAR_DEV);
rsrc_len = pci_resource_len(pdev, PCI_BAR_DEV);
res = devm_request_mem_region(dev, rsrc_start, rsrc_len, "dev");
if (!res) {
dev_dbg(dev, "controller already in use\n");
return -EBUSY;
}
priv_dev->regs = devm_ioremap(dev, rsrc_start, rsrc_len);
if (!priv_dev->regs) {
dev_dbg(dev, "error mapping memory\n");
return -EFAULT;
}
priv_dev->irq = pdev->irq;
dev_dbg(dev, "USBSS-DEV physical base addr: %pa\n",
&rsrc_start);
priv_dev->dev = dev;
priv_dev->eps_supported = 0x000f000f;
priv_dev->onchip_tx_buf = 16;
priv_dev->onchip_rx_buf = 16;
ret = cdns2_gadget_init(priv_dev);
if (ret)
return ret;
pci_set_drvdata(pdev, priv_dev);
device_wakeup_enable(&pdev->dev);
if (pci_dev_run_wake(pdev))
pm_runtime_put_noidle(&pdev->dev);
return 0;
}
static void cdns2_pci_remove(struct pci_dev *pdev)
{
struct cdns2_device *priv_dev = pci_get_drvdata(pdev);
if (pci_dev_run_wake(pdev))
pm_runtime_get_noresume(&pdev->dev);
cdns2_gadget_remove(priv_dev);
}
static int cdns2_pci_suspend(struct device *dev)
{
struct cdns2_device *priv_dev = dev_get_drvdata(dev);
return cdns2_gadget_suspend(priv_dev);
}
static int cdns2_pci_resume(struct device *dev)
{
struct cdns2_device *priv_dev = dev_get_drvdata(dev);
return cdns2_gadget_resume(priv_dev, 1);
}
static const struct dev_pm_ops cdns2_pci_pm_ops = {
SYSTEM_SLEEP_PM_OPS(cdns2_pci_suspend, cdns2_pci_resume)
};
static const struct pci_device_id cdns2_pci_ids[] = {
{ PCI_VENDOR_ID_CDNS, CDNS_DEVICE_ID, PCI_ANY_ID, PCI_ANY_ID,
PCI_CLASS_SERIAL_USB_DEVICE, PCI_ANY_ID },
{ 0, }
};
static struct pci_driver cdns2_pci_driver = {
.name = "cdns2-pci",
.id_table = &cdns2_pci_ids[0],
.probe = cdns2_pci_probe,
.remove = cdns2_pci_remove,
.driver = {
.pm = pm_ptr(&cdns2_pci_pm_ops),
}
};
module_pci_driver(cdns2_pci_driver);
MODULE_DEVICE_TABLE(pci, cdns2_pci_ids);
MODULE_ALIAS("pci:cdns2");
MODULE_AUTHOR("Pawel Laszczak <pawell@cadence.com>");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Cadence CDNS2 PCI driver");
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment