162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0+ 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * dwc3-st.c Support for dwc3 platform devices on ST Microelectronics platforms 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This is a small driver for the dwc3 to provide the glue logic 662306a36Sopenharmony_ci * to configure the controller. Tested on STi platforms. 762306a36Sopenharmony_ci * 862306a36Sopenharmony_ci * Copyright (C) 2014 Stmicroelectronics 962306a36Sopenharmony_ci * 1062306a36Sopenharmony_ci * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com> 1162306a36Sopenharmony_ci * Contributors: Aymen Bouattay <aymen.bouattay@st.com> 1262306a36Sopenharmony_ci * Peter Griffin <peter.griffin@linaro.org> 1362306a36Sopenharmony_ci * 1462306a36Sopenharmony_ci * Inspired by dwc3-omap.c and dwc3-exynos.c. 1562306a36Sopenharmony_ci */ 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_ci#include <linux/delay.h> 1862306a36Sopenharmony_ci#include <linux/interrupt.h> 1962306a36Sopenharmony_ci#include <linux/io.h> 2062306a36Sopenharmony_ci#include <linux/ioport.h> 2162306a36Sopenharmony_ci#include <linux/kernel.h> 2262306a36Sopenharmony_ci#include <linux/mfd/syscon.h> 2362306a36Sopenharmony_ci#include <linux/module.h> 2462306a36Sopenharmony_ci#include <linux/of.h> 2562306a36Sopenharmony_ci#include <linux/of_platform.h> 2662306a36Sopenharmony_ci#include <linux/platform_device.h> 2762306a36Sopenharmony_ci#include <linux/slab.h> 2862306a36Sopenharmony_ci#include <linux/regmap.h> 2962306a36Sopenharmony_ci#include <linux/reset.h> 3062306a36Sopenharmony_ci#include <linux/pinctrl/consumer.h> 3162306a36Sopenharmony_ci#include <linux/usb/of.h> 3262306a36Sopenharmony_ci 3362306a36Sopenharmony_ci#include "core.h" 3462306a36Sopenharmony_ci#include "io.h" 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci/* glue registers */ 3762306a36Sopenharmony_ci#define CLKRST_CTRL 0x00 3862306a36Sopenharmony_ci#define AUX_CLK_EN BIT(0) 3962306a36Sopenharmony_ci#define SW_PIPEW_RESET_N BIT(4) 4062306a36Sopenharmony_ci#define EXT_CFG_RESET_N BIT(8) 4162306a36Sopenharmony_ci/* 4262306a36Sopenharmony_ci * 1'b0 : The host controller complies with the xHCI revision 0.96 4362306a36Sopenharmony_ci * 1'b1 : The host controller complies with the xHCI revision 1.0 4462306a36Sopenharmony_ci */ 4562306a36Sopenharmony_ci#define XHCI_REVISION BIT(12) 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci#define USB2_VBUS_MNGMNT_SEL1 0x2C 4862306a36Sopenharmony_ci/* 4962306a36Sopenharmony_ci * For all fields in USB2_VBUS_MNGMNT_SEL1 5062306a36Sopenharmony_ci * 2’b00 : Override value from Reg 0x30 is selected 5162306a36Sopenharmony_ci * 2’b01 : utmiotg_<signal_name> from usb3_top is selected 5262306a36Sopenharmony_ci * 2’b10 : pipew_<signal_name> from PIPEW instance is selected 5362306a36Sopenharmony_ci * 2’b11 : value is 1'b0 5462306a36Sopenharmony_ci */ 5562306a36Sopenharmony_ci#define USB2_VBUS_REG30 0x0 5662306a36Sopenharmony_ci#define USB2_VBUS_UTMIOTG 0x1 5762306a36Sopenharmony_ci#define USB2_VBUS_PIPEW 0x2 5862306a36Sopenharmony_ci#define USB2_VBUS_ZERO 0x3 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci#define SEL_OVERRIDE_VBUSVALID(n) (n << 0) 6162306a36Sopenharmony_ci#define SEL_OVERRIDE_POWERPRESENT(n) (n << 4) 6262306a36Sopenharmony_ci#define SEL_OVERRIDE_BVALID(n) (n << 8) 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci/* Static DRD configuration */ 6562306a36Sopenharmony_ci#define USB3_CONTROL_MASK 0xf77 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci#define USB3_DEVICE_NOT_HOST BIT(0) 6862306a36Sopenharmony_ci#define USB3_FORCE_VBUSVALID BIT(1) 6962306a36Sopenharmony_ci#define USB3_DELAY_VBUSVALID BIT(2) 7062306a36Sopenharmony_ci#define USB3_SEL_FORCE_OPMODE BIT(4) 7162306a36Sopenharmony_ci#define USB3_FORCE_OPMODE(n) (n << 5) 7262306a36Sopenharmony_ci#define USB3_SEL_FORCE_DPPULLDOWN2 BIT(8) 7362306a36Sopenharmony_ci#define USB3_FORCE_DPPULLDOWN2 BIT(9) 7462306a36Sopenharmony_ci#define USB3_SEL_FORCE_DMPULLDOWN2 BIT(10) 7562306a36Sopenharmony_ci#define USB3_FORCE_DMPULLDOWN2 BIT(11) 7662306a36Sopenharmony_ci 7762306a36Sopenharmony_ci/** 7862306a36Sopenharmony_ci * struct st_dwc3 - dwc3-st driver private structure 7962306a36Sopenharmony_ci * @dev: device pointer 8062306a36Sopenharmony_ci * @glue_base: ioaddr for the glue registers 8162306a36Sopenharmony_ci * @regmap: regmap pointer for getting syscfg 8262306a36Sopenharmony_ci * @syscfg_reg_off: usb syscfg control offset 8362306a36Sopenharmony_ci * @dr_mode: drd static host/device config 8462306a36Sopenharmony_ci * @rstc_pwrdn: rest controller for powerdown signal 8562306a36Sopenharmony_ci * @rstc_rst: reset controller for softreset signal 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci 8862306a36Sopenharmony_cistruct st_dwc3 { 8962306a36Sopenharmony_ci struct device *dev; 9062306a36Sopenharmony_ci void __iomem *glue_base; 9162306a36Sopenharmony_ci struct regmap *regmap; 9262306a36Sopenharmony_ci int syscfg_reg_off; 9362306a36Sopenharmony_ci enum usb_dr_mode dr_mode; 9462306a36Sopenharmony_ci struct reset_control *rstc_pwrdn; 9562306a36Sopenharmony_ci struct reset_control *rstc_rst; 9662306a36Sopenharmony_ci}; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_cistatic inline u32 st_dwc3_readl(void __iomem *base, u32 offset) 9962306a36Sopenharmony_ci{ 10062306a36Sopenharmony_ci return readl_relaxed(base + offset); 10162306a36Sopenharmony_ci} 10262306a36Sopenharmony_ci 10362306a36Sopenharmony_cistatic inline void st_dwc3_writel(void __iomem *base, u32 offset, u32 value) 10462306a36Sopenharmony_ci{ 10562306a36Sopenharmony_ci writel_relaxed(value, base + offset); 10662306a36Sopenharmony_ci} 10762306a36Sopenharmony_ci 10862306a36Sopenharmony_ci/** 10962306a36Sopenharmony_ci * st_dwc3_drd_init: program the port 11062306a36Sopenharmony_ci * @dwc3_data: driver private structure 11162306a36Sopenharmony_ci * Description: this function is to program the port as either host or device 11262306a36Sopenharmony_ci * according to the static configuration passed from devicetree. 11362306a36Sopenharmony_ci * OTG and dual role are not yet supported! 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_cistatic int st_dwc3_drd_init(struct st_dwc3 *dwc3_data) 11662306a36Sopenharmony_ci{ 11762306a36Sopenharmony_ci u32 val; 11862306a36Sopenharmony_ci int err; 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci err = regmap_read(dwc3_data->regmap, dwc3_data->syscfg_reg_off, &val); 12162306a36Sopenharmony_ci if (err) 12262306a36Sopenharmony_ci return err; 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci val &= USB3_CONTROL_MASK; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci switch (dwc3_data->dr_mode) { 12762306a36Sopenharmony_ci case USB_DR_MODE_PERIPHERAL: 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci val &= ~(USB3_DELAY_VBUSVALID 13062306a36Sopenharmony_ci | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3) 13162306a36Sopenharmony_ci | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2 13262306a36Sopenharmony_ci | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci /* 13562306a36Sopenharmony_ci * USB3_PORT2_FORCE_VBUSVALID When '1' and when 13662306a36Sopenharmony_ci * USB3_PORT2_DEVICE_NOT_HOST = 1, forces VBUSVLDEXT2 input 13762306a36Sopenharmony_ci * of the pico PHY to 1. 13862306a36Sopenharmony_ci */ 13962306a36Sopenharmony_ci 14062306a36Sopenharmony_ci val |= USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID; 14162306a36Sopenharmony_ci break; 14262306a36Sopenharmony_ci 14362306a36Sopenharmony_ci case USB_DR_MODE_HOST: 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci val &= ~(USB3_DEVICE_NOT_HOST | USB3_FORCE_VBUSVALID 14662306a36Sopenharmony_ci | USB3_SEL_FORCE_OPMODE | USB3_FORCE_OPMODE(0x3) 14762306a36Sopenharmony_ci | USB3_SEL_FORCE_DPPULLDOWN2 | USB3_FORCE_DPPULLDOWN2 14862306a36Sopenharmony_ci | USB3_SEL_FORCE_DMPULLDOWN2 | USB3_FORCE_DMPULLDOWN2); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci /* 15162306a36Sopenharmony_ci * USB3_DELAY_VBUSVALID is ANDed with USB_C_VBUSVALID. Thus, 15262306a36Sopenharmony_ci * when set to ‘0‘, it can delay the arrival of VBUSVALID 15362306a36Sopenharmony_ci * information to VBUSVLDEXT2 input of the pico PHY. 15462306a36Sopenharmony_ci * We don't want to do that so we set the bit to '1'. 15562306a36Sopenharmony_ci */ 15662306a36Sopenharmony_ci 15762306a36Sopenharmony_ci val |= USB3_DELAY_VBUSVALID; 15862306a36Sopenharmony_ci break; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci default: 16162306a36Sopenharmony_ci dev_err(dwc3_data->dev, "Unsupported mode of operation %d\n", 16262306a36Sopenharmony_ci dwc3_data->dr_mode); 16362306a36Sopenharmony_ci return -EINVAL; 16462306a36Sopenharmony_ci } 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return regmap_write(dwc3_data->regmap, dwc3_data->syscfg_reg_off, val); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ci 16962306a36Sopenharmony_ci/** 17062306a36Sopenharmony_ci * st_dwc3_init: init the controller via glue logic 17162306a36Sopenharmony_ci * @dwc3_data: driver private structure 17262306a36Sopenharmony_ci */ 17362306a36Sopenharmony_cistatic void st_dwc3_init(struct st_dwc3 *dwc3_data) 17462306a36Sopenharmony_ci{ 17562306a36Sopenharmony_ci u32 reg = st_dwc3_readl(dwc3_data->glue_base, CLKRST_CTRL); 17662306a36Sopenharmony_ci 17762306a36Sopenharmony_ci reg |= AUX_CLK_EN | EXT_CFG_RESET_N | XHCI_REVISION; 17862306a36Sopenharmony_ci reg &= ~SW_PIPEW_RESET_N; 17962306a36Sopenharmony_ci st_dwc3_writel(dwc3_data->glue_base, CLKRST_CTRL, reg); 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci /* configure mux for vbus, powerpresent and bvalid signals */ 18262306a36Sopenharmony_ci reg = st_dwc3_readl(dwc3_data->glue_base, USB2_VBUS_MNGMNT_SEL1); 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci reg |= SEL_OVERRIDE_VBUSVALID(USB2_VBUS_UTMIOTG) | 18562306a36Sopenharmony_ci SEL_OVERRIDE_POWERPRESENT(USB2_VBUS_UTMIOTG) | 18662306a36Sopenharmony_ci SEL_OVERRIDE_BVALID(USB2_VBUS_UTMIOTG); 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci st_dwc3_writel(dwc3_data->glue_base, USB2_VBUS_MNGMNT_SEL1, reg); 18962306a36Sopenharmony_ci 19062306a36Sopenharmony_ci reg = st_dwc3_readl(dwc3_data->glue_base, CLKRST_CTRL); 19162306a36Sopenharmony_ci reg |= SW_PIPEW_RESET_N; 19262306a36Sopenharmony_ci st_dwc3_writel(dwc3_data->glue_base, CLKRST_CTRL, reg); 19362306a36Sopenharmony_ci} 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_cistatic int st_dwc3_probe(struct platform_device *pdev) 19662306a36Sopenharmony_ci{ 19762306a36Sopenharmony_ci struct st_dwc3 *dwc3_data; 19862306a36Sopenharmony_ci struct resource *res; 19962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 20062306a36Sopenharmony_ci struct device_node *node = dev->of_node, *child; 20162306a36Sopenharmony_ci struct platform_device *child_pdev; 20262306a36Sopenharmony_ci struct regmap *regmap; 20362306a36Sopenharmony_ci int ret; 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci dwc3_data = devm_kzalloc(dev, sizeof(*dwc3_data), GFP_KERNEL); 20662306a36Sopenharmony_ci if (!dwc3_data) 20762306a36Sopenharmony_ci return -ENOMEM; 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci dwc3_data->glue_base = 21062306a36Sopenharmony_ci devm_platform_ioremap_resource_byname(pdev, "reg-glue"); 21162306a36Sopenharmony_ci if (IS_ERR(dwc3_data->glue_base)) 21262306a36Sopenharmony_ci return PTR_ERR(dwc3_data->glue_base); 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci regmap = syscon_regmap_lookup_by_phandle(node, "st,syscfg"); 21562306a36Sopenharmony_ci if (IS_ERR(regmap)) 21662306a36Sopenharmony_ci return PTR_ERR(regmap); 21762306a36Sopenharmony_ci 21862306a36Sopenharmony_ci dwc3_data->dev = dev; 21962306a36Sopenharmony_ci dwc3_data->regmap = regmap; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "syscfg-reg"); 22262306a36Sopenharmony_ci if (!res) { 22362306a36Sopenharmony_ci ret = -ENXIO; 22462306a36Sopenharmony_ci goto undo_platform_dev_alloc; 22562306a36Sopenharmony_ci } 22662306a36Sopenharmony_ci 22762306a36Sopenharmony_ci dwc3_data->syscfg_reg_off = res->start; 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci dev_vdbg(&pdev->dev, "glue-logic addr 0x%pK, syscfg-reg offset 0x%x\n", 23062306a36Sopenharmony_ci dwc3_data->glue_base, dwc3_data->syscfg_reg_off); 23162306a36Sopenharmony_ci 23262306a36Sopenharmony_ci dwc3_data->rstc_pwrdn = 23362306a36Sopenharmony_ci devm_reset_control_get_exclusive(dev, "powerdown"); 23462306a36Sopenharmony_ci if (IS_ERR(dwc3_data->rstc_pwrdn)) { 23562306a36Sopenharmony_ci dev_err(&pdev->dev, "could not get power controller\n"); 23662306a36Sopenharmony_ci ret = PTR_ERR(dwc3_data->rstc_pwrdn); 23762306a36Sopenharmony_ci goto undo_platform_dev_alloc; 23862306a36Sopenharmony_ci } 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci /* Manage PowerDown */ 24162306a36Sopenharmony_ci reset_control_deassert(dwc3_data->rstc_pwrdn); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci dwc3_data->rstc_rst = 24462306a36Sopenharmony_ci devm_reset_control_get_shared(dev, "softreset"); 24562306a36Sopenharmony_ci if (IS_ERR(dwc3_data->rstc_rst)) { 24662306a36Sopenharmony_ci dev_err(&pdev->dev, "could not get reset controller\n"); 24762306a36Sopenharmony_ci ret = PTR_ERR(dwc3_data->rstc_rst); 24862306a36Sopenharmony_ci goto undo_powerdown; 24962306a36Sopenharmony_ci } 25062306a36Sopenharmony_ci 25162306a36Sopenharmony_ci /* Manage SoftReset */ 25262306a36Sopenharmony_ci reset_control_deassert(dwc3_data->rstc_rst); 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci child = of_get_compatible_child(node, "snps,dwc3"); 25562306a36Sopenharmony_ci if (!child) { 25662306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to find dwc3 core node\n"); 25762306a36Sopenharmony_ci ret = -ENODEV; 25862306a36Sopenharmony_ci goto err_node_put; 25962306a36Sopenharmony_ci } 26062306a36Sopenharmony_ci 26162306a36Sopenharmony_ci /* Allocate and initialize the core */ 26262306a36Sopenharmony_ci ret = of_platform_populate(node, NULL, NULL, dev); 26362306a36Sopenharmony_ci if (ret) { 26462306a36Sopenharmony_ci dev_err(dev, "failed to add dwc3 core\n"); 26562306a36Sopenharmony_ci goto err_node_put; 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci child_pdev = of_find_device_by_node(child); 26962306a36Sopenharmony_ci if (!child_pdev) { 27062306a36Sopenharmony_ci dev_err(dev, "failed to find dwc3 core device\n"); 27162306a36Sopenharmony_ci ret = -ENODEV; 27262306a36Sopenharmony_ci goto err_node_put; 27362306a36Sopenharmony_ci } 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci dwc3_data->dr_mode = usb_get_dr_mode(&child_pdev->dev); 27662306a36Sopenharmony_ci of_node_put(child); 27762306a36Sopenharmony_ci platform_device_put(child_pdev); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_ci /* 28062306a36Sopenharmony_ci * Configure the USB port as device or host according to the static 28162306a36Sopenharmony_ci * configuration passed from DT. 28262306a36Sopenharmony_ci * DRD is the only mode currently supported so this will be enhanced 28362306a36Sopenharmony_ci * as soon as OTG is available. 28462306a36Sopenharmony_ci */ 28562306a36Sopenharmony_ci ret = st_dwc3_drd_init(dwc3_data); 28662306a36Sopenharmony_ci if (ret) { 28762306a36Sopenharmony_ci dev_err(dev, "drd initialisation failed\n"); 28862306a36Sopenharmony_ci goto undo_softreset; 28962306a36Sopenharmony_ci } 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* ST glue logic init */ 29262306a36Sopenharmony_ci st_dwc3_init(dwc3_data); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci platform_set_drvdata(pdev, dwc3_data); 29562306a36Sopenharmony_ci return 0; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_cierr_node_put: 29862306a36Sopenharmony_ci of_node_put(child); 29962306a36Sopenharmony_ciundo_softreset: 30062306a36Sopenharmony_ci reset_control_assert(dwc3_data->rstc_rst); 30162306a36Sopenharmony_ciundo_powerdown: 30262306a36Sopenharmony_ci reset_control_assert(dwc3_data->rstc_pwrdn); 30362306a36Sopenharmony_ciundo_platform_dev_alloc: 30462306a36Sopenharmony_ci platform_device_put(pdev); 30562306a36Sopenharmony_ci return ret; 30662306a36Sopenharmony_ci} 30762306a36Sopenharmony_ci 30862306a36Sopenharmony_cistatic void st_dwc3_remove(struct platform_device *pdev) 30962306a36Sopenharmony_ci{ 31062306a36Sopenharmony_ci struct st_dwc3 *dwc3_data = platform_get_drvdata(pdev); 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_ci of_platform_depopulate(&pdev->dev); 31362306a36Sopenharmony_ci 31462306a36Sopenharmony_ci reset_control_assert(dwc3_data->rstc_pwrdn); 31562306a36Sopenharmony_ci reset_control_assert(dwc3_data->rstc_rst); 31662306a36Sopenharmony_ci} 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci#ifdef CONFIG_PM_SLEEP 31962306a36Sopenharmony_cistatic int st_dwc3_suspend(struct device *dev) 32062306a36Sopenharmony_ci{ 32162306a36Sopenharmony_ci struct st_dwc3 *dwc3_data = dev_get_drvdata(dev); 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci reset_control_assert(dwc3_data->rstc_pwrdn); 32462306a36Sopenharmony_ci reset_control_assert(dwc3_data->rstc_rst); 32562306a36Sopenharmony_ci 32662306a36Sopenharmony_ci pinctrl_pm_select_sleep_state(dev); 32762306a36Sopenharmony_ci 32862306a36Sopenharmony_ci return 0; 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_cistatic int st_dwc3_resume(struct device *dev) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci struct st_dwc3 *dwc3_data = dev_get_drvdata(dev); 33462306a36Sopenharmony_ci int ret; 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci pinctrl_pm_select_default_state(dev); 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci reset_control_deassert(dwc3_data->rstc_pwrdn); 33962306a36Sopenharmony_ci reset_control_deassert(dwc3_data->rstc_rst); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci ret = st_dwc3_drd_init(dwc3_data); 34262306a36Sopenharmony_ci if (ret) { 34362306a36Sopenharmony_ci dev_err(dev, "drd initialisation failed\n"); 34462306a36Sopenharmony_ci return ret; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_ci /* ST glue logic init */ 34862306a36Sopenharmony_ci st_dwc3_init(dwc3_data); 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci return 0; 35162306a36Sopenharmony_ci} 35262306a36Sopenharmony_ci#endif /* CONFIG_PM_SLEEP */ 35362306a36Sopenharmony_ci 35462306a36Sopenharmony_cistatic SIMPLE_DEV_PM_OPS(st_dwc3_dev_pm_ops, st_dwc3_suspend, st_dwc3_resume); 35562306a36Sopenharmony_ci 35662306a36Sopenharmony_cistatic const struct of_device_id st_dwc3_match[] = { 35762306a36Sopenharmony_ci { .compatible = "st,stih407-dwc3" }, 35862306a36Sopenharmony_ci { /* sentinel */ }, 35962306a36Sopenharmony_ci}; 36062306a36Sopenharmony_ci 36162306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, st_dwc3_match); 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic struct platform_driver st_dwc3_driver = { 36462306a36Sopenharmony_ci .probe = st_dwc3_probe, 36562306a36Sopenharmony_ci .remove_new = st_dwc3_remove, 36662306a36Sopenharmony_ci .driver = { 36762306a36Sopenharmony_ci .name = "usb-st-dwc3", 36862306a36Sopenharmony_ci .of_match_table = st_dwc3_match, 36962306a36Sopenharmony_ci .pm = &st_dwc3_dev_pm_ops, 37062306a36Sopenharmony_ci }, 37162306a36Sopenharmony_ci}; 37262306a36Sopenharmony_ci 37362306a36Sopenharmony_cimodule_platform_driver(st_dwc3_driver); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ciMODULE_AUTHOR("Giuseppe Cavallaro <peppe.cavallaro@st.com>"); 37662306a36Sopenharmony_ciMODULE_DESCRIPTION("DesignWare USB3 STi Glue Layer"); 37762306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 378