Traditionally, platforms-specific glue was abstracted as a separate parent device tree node for the snps,dwc3 node. For some newer integrations, this is no longer the case and there is only a single (flattened) node. To prepare support for these drivers, export the probe and remove functions with the Linux semantics.
Signed-off-by: Ahmad Fatoum <[email protected]> --- drivers/usb/dwc3/core.c | 78 ++++++++++++++++++++++++++++------------- drivers/usb/dwc3/glue.h | 49 ++++++++++++++++++++++++++ 2 files changed, 102 insertions(+), 25 deletions(-) create mode 100644 drivers/usb/dwc3/glue.h diff --git a/drivers/usb/dwc3/core.c b/drivers/usb/dwc3/core.c index 7f2cb6c4a70a..472630c95392 100644 --- a/drivers/usb/dwc3/core.c +++ b/drivers/usb/dwc3/core.c @@ -17,6 +17,7 @@ #include <linux/reset.h> #include <linux/usb/of.h> +#include "glue.h" #include "core.h" #include "gadget.h" #include "io.h" @@ -1402,41 +1403,43 @@ static void dwc3_check_params(struct dwc3 *dwc) } } -static int dwc3_probe(struct device *dev) +int dwc3_core_probe(const struct dwc3_probe_data *data) { - struct dwc3 *dwc; + struct dwc3 *dwc = data->dwc; + struct device *dev = dwc->dev; + struct resource *res = data->res; int ret; - dwc = xzalloc(sizeof(*dwc)); dev->priv = dwc; - dwc->dev = dev; - dwc->regs = dev_get_mem_region(dwc->dev, 0) + DWC3_GLOBALS_REGS_START; + dwc->regs = IOMEM(res->start) + DWC3_GLOBALS_REGS_START; dwc3_get_properties(dwc); - if (dev->of_node) { - ret = clk_bulk_get_all(dev, &dwc->clks); - if (ret < 0) + if (!data->ignore_clocks_and_resets) { + if (dev->of_node) { + ret = clk_bulk_get_all(dev, &dwc->clks); + if (ret < 0) + return ret; + + dwc->num_clks = ret; + } + + ret = clk_bulk_enable(dwc->num_clks, dwc->clks); + if (ret) return ret; - dwc->num_clks = ret; + dwc->reset = reset_control_get(dev, NULL); + if (IS_ERR(dwc->reset)) { + dev_err(dev, "Failed to get reset control: %pe\n", dwc->reset); + return PTR_ERR(dwc->reset); + } + + reset_control_assert(dwc->reset); + mdelay(1); + reset_control_deassert(dwc->reset); } - ret = clk_bulk_enable(dwc->num_clks, dwc->clks); - if (ret) - return ret; - - dwc->reset = reset_control_get(dev, NULL); - if (IS_ERR(dwc->reset)) { - dev_err(dev, "Failed to get reset control: %pe\n", dwc->reset); - return PTR_ERR(dwc->reset); - } - - reset_control_assert(dwc->reset); - mdelay(1); - reset_control_deassert(dwc->reset); - if (!dwc3_core_is_valid(dwc)) { dev_err(dwc->dev, "this is not a DesignWare USB3 DRD Core\n"); return -ENODEV; @@ -1476,10 +1479,30 @@ static int dwc3_probe(struct device *dev) return 0; } -static void dwc3_remove(struct device *dev) +static int dwc3_probe(struct device *dev) { - struct dwc3 *dwc = dev->priv; + struct dwc3_probe_data probe_data = {}; + struct resource *res; + struct dwc3 *dwc; + res = dev_get_resource(dev, IORESOURCE_MEM, 0); + if (!res) { + dev_err(dev, "missing memory resource\n"); + return -ENODEV; + } + + dwc = xzalloc(sizeof(*dwc)); + + dwc->dev = dev; + + probe_data.dwc = dwc; + probe_data.res = res; + + return dwc3_core_probe(&probe_data); +} + +void dwc3_core_remove(struct dwc3 *dwc) +{ dwc3_core_exit_mode(dwc); dwc3_core_exit(dwc); clk_bulk_put(dwc->num_clks, dwc->clks); @@ -1487,6 +1510,11 @@ static void dwc3_remove(struct device *dev) dwc3_free_scratch_buffers(dwc); } +static void dwc3_remove(struct device *dev) +{ + dwc3_core_remove(dev->priv); +} + static const struct of_device_id of_dwc3_match[] = { { .compatible = "snps,dwc3", diff --git a/drivers/usb/dwc3/glue.h b/drivers/usb/dwc3/glue.h new file mode 100644 index 000000000000..05d6d2723d19 --- /dev/null +++ b/drivers/usb/dwc3/glue.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * glue.h - DesignWare USB3 DRD glue header + */ + +#ifndef __DRIVERS_USB_DWC3_GLUE_H +#define __DRIVERS_USB_DWC3_GLUE_H + +#include <linux/types.h> +#include "core.h" + +/** + * dwc3_probe_data: Initialization parameters passed to dwc3_core_probe() + * @dwc: Reference to dwc3 context structure + * @res: resource for the DWC3 core mmio region + * @ignore_clocks_and_resets: clocks and resets defined for the device should + * be ignored by the DWC3 core, as they are managed by the glue + */ +struct dwc3_probe_data { + struct dwc3 *dwc; + struct resource *res; + bool ignore_clocks_and_resets; +}; + +/** + * dwc3_core_probe - Initialize the core dwc3 driver + * @data: Initialization and configuration parameters for the controller + * + * Initializes the DesignWare USB3 core driver by setting up resources, + * registering interrupts, performing hardware setup, and preparing + * the controller for operation in the appropriate mode (host, gadget, + * or OTG). This is the main initialization function called by glue + * layer drivers to set up the core controller. + * + * Return: 0 on success, negative error code on failure + */ +int dwc3_core_probe(const struct dwc3_probe_data *data); + +/** + * dwc3_core_remove - Deinitialize and remove the core dwc3 driver + * @dwc: Pointer to DWC3 controller context + * + * Cleans up resources and disables the dwc3 core driver. This should be called + * during driver removal or when the glue layer needs to shut down the + * controller completely. + */ +void dwc3_core_remove(struct dwc3 *dwc); + +#endif -- 2.47.3
