162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * dwc3-imx8mp.c - NXP imx8mp Specific Glue layer 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2020 NXP. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#include <linux/clk.h> 962306a36Sopenharmony_ci#include <linux/interrupt.h> 1062306a36Sopenharmony_ci#include <linux/io.h> 1162306a36Sopenharmony_ci#include <linux/kernel.h> 1262306a36Sopenharmony_ci#include <linux/module.h> 1362306a36Sopenharmony_ci#include <linux/of.h> 1462306a36Sopenharmony_ci#include <linux/of_platform.h> 1562306a36Sopenharmony_ci#include <linux/platform_device.h> 1662306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1762306a36Sopenharmony_ci 1862306a36Sopenharmony_ci#include "core.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/* USB wakeup registers */ 2162306a36Sopenharmony_ci#define USB_WAKEUP_CTRL 0x00 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_ci/* Global wakeup interrupt enable, also used to clear interrupt */ 2462306a36Sopenharmony_ci#define USB_WAKEUP_EN BIT(31) 2562306a36Sopenharmony_ci/* Wakeup from connect or disconnect, only for superspeed */ 2662306a36Sopenharmony_ci#define USB_WAKEUP_SS_CONN BIT(5) 2762306a36Sopenharmony_ci/* 0 select vbus_valid, 1 select sessvld */ 2862306a36Sopenharmony_ci#define USB_WAKEUP_VBUS_SRC_SESS_VAL BIT(4) 2962306a36Sopenharmony_ci/* Enable signal for wake up from u3 state */ 3062306a36Sopenharmony_ci#define USB_WAKEUP_U3_EN BIT(3) 3162306a36Sopenharmony_ci/* Enable signal for wake up from id change */ 3262306a36Sopenharmony_ci#define USB_WAKEUP_ID_EN BIT(2) 3362306a36Sopenharmony_ci/* Enable signal for wake up from vbus change */ 3462306a36Sopenharmony_ci#define USB_WAKEUP_VBUS_EN BIT(1) 3562306a36Sopenharmony_ci/* Enable signal for wake up from dp/dm change */ 3662306a36Sopenharmony_ci#define USB_WAKEUP_DPDM_EN BIT(0) 3762306a36Sopenharmony_ci 3862306a36Sopenharmony_ci#define USB_WAKEUP_EN_MASK GENMASK(5, 0) 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_ci/* USB glue registers */ 4162306a36Sopenharmony_ci#define USB_CTRL0 0x00 4262306a36Sopenharmony_ci#define USB_CTRL1 0x04 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci#define USB_CTRL0_PORTPWR_EN BIT(12) /* 1 - PPC enabled (default) */ 4562306a36Sopenharmony_ci#define USB_CTRL0_USB3_FIXED BIT(22) /* 1 - USB3 permanent attached */ 4662306a36Sopenharmony_ci#define USB_CTRL0_USB2_FIXED BIT(23) /* 1 - USB2 permanent attached */ 4762306a36Sopenharmony_ci 4862306a36Sopenharmony_ci#define USB_CTRL1_OC_POLARITY BIT(16) /* 0 - HIGH / 1 - LOW */ 4962306a36Sopenharmony_ci#define USB_CTRL1_PWR_POLARITY BIT(17) /* 0 - HIGH / 1 - LOW */ 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_cistruct dwc3_imx8mp { 5262306a36Sopenharmony_ci struct device *dev; 5362306a36Sopenharmony_ci struct platform_device *dwc3; 5462306a36Sopenharmony_ci void __iomem *hsio_blk_base; 5562306a36Sopenharmony_ci void __iomem *glue_base; 5662306a36Sopenharmony_ci struct clk *hsio_clk; 5762306a36Sopenharmony_ci struct clk *suspend_clk; 5862306a36Sopenharmony_ci int irq; 5962306a36Sopenharmony_ci bool pm_suspended; 6062306a36Sopenharmony_ci bool wakeup_pending; 6162306a36Sopenharmony_ci}; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_cistatic void imx8mp_configure_glue(struct dwc3_imx8mp *dwc3_imx) 6462306a36Sopenharmony_ci{ 6562306a36Sopenharmony_ci struct device *dev = dwc3_imx->dev; 6662306a36Sopenharmony_ci u32 value; 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_ci if (!dwc3_imx->glue_base) 6962306a36Sopenharmony_ci return; 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci value = readl(dwc3_imx->glue_base + USB_CTRL0); 7262306a36Sopenharmony_ci 7362306a36Sopenharmony_ci if (device_property_read_bool(dev, "fsl,permanently-attached")) 7462306a36Sopenharmony_ci value |= (USB_CTRL0_USB2_FIXED | USB_CTRL0_USB3_FIXED); 7562306a36Sopenharmony_ci else 7662306a36Sopenharmony_ci value &= ~(USB_CTRL0_USB2_FIXED | USB_CTRL0_USB3_FIXED); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ci if (device_property_read_bool(dev, "fsl,disable-port-power-control")) 7962306a36Sopenharmony_ci value &= ~(USB_CTRL0_PORTPWR_EN); 8062306a36Sopenharmony_ci else 8162306a36Sopenharmony_ci value |= USB_CTRL0_PORTPWR_EN; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci writel(value, dwc3_imx->glue_base + USB_CTRL0); 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_ci value = readl(dwc3_imx->glue_base + USB_CTRL1); 8662306a36Sopenharmony_ci if (device_property_read_bool(dev, "fsl,over-current-active-low")) 8762306a36Sopenharmony_ci value |= USB_CTRL1_OC_POLARITY; 8862306a36Sopenharmony_ci else 8962306a36Sopenharmony_ci value &= ~USB_CTRL1_OC_POLARITY; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci if (device_property_read_bool(dev, "fsl,power-active-low")) 9262306a36Sopenharmony_ci value |= USB_CTRL1_PWR_POLARITY; 9362306a36Sopenharmony_ci else 9462306a36Sopenharmony_ci value &= ~USB_CTRL1_PWR_POLARITY; 9562306a36Sopenharmony_ci 9662306a36Sopenharmony_ci writel(value, dwc3_imx->glue_base + USB_CTRL1); 9762306a36Sopenharmony_ci} 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_cistatic void dwc3_imx8mp_wakeup_enable(struct dwc3_imx8mp *dwc3_imx) 10062306a36Sopenharmony_ci{ 10162306a36Sopenharmony_ci struct dwc3 *dwc3 = platform_get_drvdata(dwc3_imx->dwc3); 10262306a36Sopenharmony_ci u32 val; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (!dwc3) 10562306a36Sopenharmony_ci return; 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci val = readl(dwc3_imx->hsio_blk_base + USB_WAKEUP_CTRL); 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_ci if ((dwc3->current_dr_role == DWC3_GCTL_PRTCAP_HOST) && dwc3->xhci) 11062306a36Sopenharmony_ci val |= USB_WAKEUP_EN | USB_WAKEUP_SS_CONN | 11162306a36Sopenharmony_ci USB_WAKEUP_U3_EN | USB_WAKEUP_DPDM_EN; 11262306a36Sopenharmony_ci else if (dwc3->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE) 11362306a36Sopenharmony_ci val |= USB_WAKEUP_EN | USB_WAKEUP_VBUS_EN | 11462306a36Sopenharmony_ci USB_WAKEUP_VBUS_SRC_SESS_VAL; 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ci writel(val, dwc3_imx->hsio_blk_base + USB_WAKEUP_CTRL); 11762306a36Sopenharmony_ci} 11862306a36Sopenharmony_ci 11962306a36Sopenharmony_cistatic void dwc3_imx8mp_wakeup_disable(struct dwc3_imx8mp *dwc3_imx) 12062306a36Sopenharmony_ci{ 12162306a36Sopenharmony_ci u32 val; 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci val = readl(dwc3_imx->hsio_blk_base + USB_WAKEUP_CTRL); 12462306a36Sopenharmony_ci val &= ~(USB_WAKEUP_EN | USB_WAKEUP_EN_MASK); 12562306a36Sopenharmony_ci writel(val, dwc3_imx->hsio_blk_base + USB_WAKEUP_CTRL); 12662306a36Sopenharmony_ci} 12762306a36Sopenharmony_ci 12862306a36Sopenharmony_cistatic irqreturn_t dwc3_imx8mp_interrupt(int irq, void *_dwc3_imx) 12962306a36Sopenharmony_ci{ 13062306a36Sopenharmony_ci struct dwc3_imx8mp *dwc3_imx = _dwc3_imx; 13162306a36Sopenharmony_ci struct dwc3 *dwc = platform_get_drvdata(dwc3_imx->dwc3); 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci if (!dwc3_imx->pm_suspended) 13462306a36Sopenharmony_ci return IRQ_HANDLED; 13562306a36Sopenharmony_ci 13662306a36Sopenharmony_ci disable_irq_nosync(dwc3_imx->irq); 13762306a36Sopenharmony_ci dwc3_imx->wakeup_pending = true; 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_ci if ((dwc->current_dr_role == DWC3_GCTL_PRTCAP_HOST) && dwc->xhci) 14062306a36Sopenharmony_ci pm_runtime_resume(&dwc->xhci->dev); 14162306a36Sopenharmony_ci else if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE) 14262306a36Sopenharmony_ci pm_runtime_get(dwc->dev); 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci return IRQ_HANDLED; 14562306a36Sopenharmony_ci} 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_cistatic int dwc3_imx8mp_probe(struct platform_device *pdev) 14862306a36Sopenharmony_ci{ 14962306a36Sopenharmony_ci struct device *dev = &pdev->dev; 15062306a36Sopenharmony_ci struct device_node *dwc3_np, *node = dev->of_node; 15162306a36Sopenharmony_ci struct dwc3_imx8mp *dwc3_imx; 15262306a36Sopenharmony_ci struct resource *res; 15362306a36Sopenharmony_ci int err, irq; 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_ci if (!node) { 15662306a36Sopenharmony_ci dev_err(dev, "device node not found\n"); 15762306a36Sopenharmony_ci return -EINVAL; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci dwc3_imx = devm_kzalloc(dev, sizeof(*dwc3_imx), GFP_KERNEL); 16162306a36Sopenharmony_ci if (!dwc3_imx) 16262306a36Sopenharmony_ci return -ENOMEM; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci platform_set_drvdata(pdev, dwc3_imx); 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci dwc3_imx->dev = dev; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci dwc3_imx->hsio_blk_base = devm_platform_ioremap_resource(pdev, 0); 16962306a36Sopenharmony_ci if (IS_ERR(dwc3_imx->hsio_blk_base)) 17062306a36Sopenharmony_ci return PTR_ERR(dwc3_imx->hsio_blk_base); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 17362306a36Sopenharmony_ci if (!res) { 17462306a36Sopenharmony_ci dev_warn(dev, "Base address for glue layer missing. Continuing without, some features are missing though."); 17562306a36Sopenharmony_ci } else { 17662306a36Sopenharmony_ci dwc3_imx->glue_base = devm_ioremap_resource(dev, res); 17762306a36Sopenharmony_ci if (IS_ERR(dwc3_imx->glue_base)) 17862306a36Sopenharmony_ci return PTR_ERR(dwc3_imx->glue_base); 17962306a36Sopenharmony_ci } 18062306a36Sopenharmony_ci 18162306a36Sopenharmony_ci dwc3_imx->hsio_clk = devm_clk_get(dev, "hsio"); 18262306a36Sopenharmony_ci if (IS_ERR(dwc3_imx->hsio_clk)) { 18362306a36Sopenharmony_ci err = PTR_ERR(dwc3_imx->hsio_clk); 18462306a36Sopenharmony_ci dev_err(dev, "Failed to get hsio clk, err=%d\n", err); 18562306a36Sopenharmony_ci return err; 18662306a36Sopenharmony_ci } 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci err = clk_prepare_enable(dwc3_imx->hsio_clk); 18962306a36Sopenharmony_ci if (err) { 19062306a36Sopenharmony_ci dev_err(dev, "Failed to enable hsio clk, err=%d\n", err); 19162306a36Sopenharmony_ci return err; 19262306a36Sopenharmony_ci } 19362306a36Sopenharmony_ci 19462306a36Sopenharmony_ci dwc3_imx->suspend_clk = devm_clk_get(dev, "suspend"); 19562306a36Sopenharmony_ci if (IS_ERR(dwc3_imx->suspend_clk)) { 19662306a36Sopenharmony_ci err = PTR_ERR(dwc3_imx->suspend_clk); 19762306a36Sopenharmony_ci dev_err(dev, "Failed to get suspend clk, err=%d\n", err); 19862306a36Sopenharmony_ci goto disable_hsio_clk; 19962306a36Sopenharmony_ci } 20062306a36Sopenharmony_ci 20162306a36Sopenharmony_ci err = clk_prepare_enable(dwc3_imx->suspend_clk); 20262306a36Sopenharmony_ci if (err) { 20362306a36Sopenharmony_ci dev_err(dev, "Failed to enable suspend clk, err=%d\n", err); 20462306a36Sopenharmony_ci goto disable_hsio_clk; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci irq = platform_get_irq(pdev, 0); 20862306a36Sopenharmony_ci if (irq < 0) { 20962306a36Sopenharmony_ci err = irq; 21062306a36Sopenharmony_ci goto disable_clks; 21162306a36Sopenharmony_ci } 21262306a36Sopenharmony_ci dwc3_imx->irq = irq; 21362306a36Sopenharmony_ci 21462306a36Sopenharmony_ci imx8mp_configure_glue(dwc3_imx); 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci pm_runtime_set_active(dev); 21762306a36Sopenharmony_ci pm_runtime_enable(dev); 21862306a36Sopenharmony_ci err = pm_runtime_get_sync(dev); 21962306a36Sopenharmony_ci if (err < 0) 22062306a36Sopenharmony_ci goto disable_rpm; 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci dwc3_np = of_get_compatible_child(node, "snps,dwc3"); 22362306a36Sopenharmony_ci if (!dwc3_np) { 22462306a36Sopenharmony_ci err = -ENODEV; 22562306a36Sopenharmony_ci dev_err(dev, "failed to find dwc3 core child\n"); 22662306a36Sopenharmony_ci goto disable_rpm; 22762306a36Sopenharmony_ci } 22862306a36Sopenharmony_ci 22962306a36Sopenharmony_ci err = of_platform_populate(node, NULL, NULL, dev); 23062306a36Sopenharmony_ci if (err) { 23162306a36Sopenharmony_ci dev_err(&pdev->dev, "failed to create dwc3 core\n"); 23262306a36Sopenharmony_ci goto err_node_put; 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci dwc3_imx->dwc3 = of_find_device_by_node(dwc3_np); 23662306a36Sopenharmony_ci if (!dwc3_imx->dwc3) { 23762306a36Sopenharmony_ci dev_err(dev, "failed to get dwc3 platform device\n"); 23862306a36Sopenharmony_ci err = -ENODEV; 23962306a36Sopenharmony_ci goto depopulate; 24062306a36Sopenharmony_ci } 24162306a36Sopenharmony_ci of_node_put(dwc3_np); 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci err = devm_request_threaded_irq(dev, irq, NULL, dwc3_imx8mp_interrupt, 24462306a36Sopenharmony_ci IRQF_ONESHOT, dev_name(dev), dwc3_imx); 24562306a36Sopenharmony_ci if (err) { 24662306a36Sopenharmony_ci dev_err(dev, "failed to request IRQ #%d --> %d\n", irq, err); 24762306a36Sopenharmony_ci goto depopulate; 24862306a36Sopenharmony_ci } 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci device_set_wakeup_capable(dev, true); 25162306a36Sopenharmony_ci pm_runtime_put(dev); 25262306a36Sopenharmony_ci 25362306a36Sopenharmony_ci return 0; 25462306a36Sopenharmony_ci 25562306a36Sopenharmony_cidepopulate: 25662306a36Sopenharmony_ci of_platform_depopulate(dev); 25762306a36Sopenharmony_cierr_node_put: 25862306a36Sopenharmony_ci of_node_put(dwc3_np); 25962306a36Sopenharmony_cidisable_rpm: 26062306a36Sopenharmony_ci pm_runtime_disable(dev); 26162306a36Sopenharmony_ci pm_runtime_put_noidle(dev); 26262306a36Sopenharmony_cidisable_clks: 26362306a36Sopenharmony_ci clk_disable_unprepare(dwc3_imx->suspend_clk); 26462306a36Sopenharmony_cidisable_hsio_clk: 26562306a36Sopenharmony_ci clk_disable_unprepare(dwc3_imx->hsio_clk); 26662306a36Sopenharmony_ci 26762306a36Sopenharmony_ci return err; 26862306a36Sopenharmony_ci} 26962306a36Sopenharmony_ci 27062306a36Sopenharmony_cistatic void dwc3_imx8mp_remove(struct platform_device *pdev) 27162306a36Sopenharmony_ci{ 27262306a36Sopenharmony_ci struct dwc3_imx8mp *dwc3_imx = platform_get_drvdata(pdev); 27362306a36Sopenharmony_ci struct device *dev = &pdev->dev; 27462306a36Sopenharmony_ci 27562306a36Sopenharmony_ci pm_runtime_get_sync(dev); 27662306a36Sopenharmony_ci of_platform_depopulate(dev); 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci clk_disable_unprepare(dwc3_imx->suspend_clk); 27962306a36Sopenharmony_ci clk_disable_unprepare(dwc3_imx->hsio_clk); 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci pm_runtime_disable(dev); 28262306a36Sopenharmony_ci pm_runtime_put_noidle(dev); 28362306a36Sopenharmony_ci} 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_cistatic int __maybe_unused dwc3_imx8mp_suspend(struct dwc3_imx8mp *dwc3_imx, 28662306a36Sopenharmony_ci pm_message_t msg) 28762306a36Sopenharmony_ci{ 28862306a36Sopenharmony_ci if (dwc3_imx->pm_suspended) 28962306a36Sopenharmony_ci return 0; 29062306a36Sopenharmony_ci 29162306a36Sopenharmony_ci /* Wakeup enable */ 29262306a36Sopenharmony_ci if (PMSG_IS_AUTO(msg) || device_may_wakeup(dwc3_imx->dev)) 29362306a36Sopenharmony_ci dwc3_imx8mp_wakeup_enable(dwc3_imx); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci dwc3_imx->pm_suspended = true; 29662306a36Sopenharmony_ci 29762306a36Sopenharmony_ci return 0; 29862306a36Sopenharmony_ci} 29962306a36Sopenharmony_ci 30062306a36Sopenharmony_cistatic int __maybe_unused dwc3_imx8mp_resume(struct dwc3_imx8mp *dwc3_imx, 30162306a36Sopenharmony_ci pm_message_t msg) 30262306a36Sopenharmony_ci{ 30362306a36Sopenharmony_ci struct dwc3 *dwc = platform_get_drvdata(dwc3_imx->dwc3); 30462306a36Sopenharmony_ci int ret = 0; 30562306a36Sopenharmony_ci 30662306a36Sopenharmony_ci if (!dwc3_imx->pm_suspended) 30762306a36Sopenharmony_ci return 0; 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci /* Wakeup disable */ 31062306a36Sopenharmony_ci dwc3_imx8mp_wakeup_disable(dwc3_imx); 31162306a36Sopenharmony_ci dwc3_imx->pm_suspended = false; 31262306a36Sopenharmony_ci 31362306a36Sopenharmony_ci /* Upon power loss any previous configuration is lost, restore it */ 31462306a36Sopenharmony_ci imx8mp_configure_glue(dwc3_imx); 31562306a36Sopenharmony_ci 31662306a36Sopenharmony_ci if (dwc3_imx->wakeup_pending) { 31762306a36Sopenharmony_ci dwc3_imx->wakeup_pending = false; 31862306a36Sopenharmony_ci if (dwc->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE) { 31962306a36Sopenharmony_ci pm_runtime_mark_last_busy(dwc->dev); 32062306a36Sopenharmony_ci pm_runtime_put_autosuspend(dwc->dev); 32162306a36Sopenharmony_ci } else { 32262306a36Sopenharmony_ci /* 32362306a36Sopenharmony_ci * Add wait for xhci switch from suspend 32462306a36Sopenharmony_ci * clock to normal clock to detect connection. 32562306a36Sopenharmony_ci */ 32662306a36Sopenharmony_ci usleep_range(9000, 10000); 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci enable_irq(dwc3_imx->irq); 32962306a36Sopenharmony_ci } 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci return ret; 33262306a36Sopenharmony_ci} 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_cistatic int __maybe_unused dwc3_imx8mp_pm_suspend(struct device *dev) 33562306a36Sopenharmony_ci{ 33662306a36Sopenharmony_ci struct dwc3_imx8mp *dwc3_imx = dev_get_drvdata(dev); 33762306a36Sopenharmony_ci int ret; 33862306a36Sopenharmony_ci 33962306a36Sopenharmony_ci ret = dwc3_imx8mp_suspend(dwc3_imx, PMSG_SUSPEND); 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci if (device_may_wakeup(dwc3_imx->dev)) 34262306a36Sopenharmony_ci enable_irq_wake(dwc3_imx->irq); 34362306a36Sopenharmony_ci else 34462306a36Sopenharmony_ci clk_disable_unprepare(dwc3_imx->suspend_clk); 34562306a36Sopenharmony_ci 34662306a36Sopenharmony_ci clk_disable_unprepare(dwc3_imx->hsio_clk); 34762306a36Sopenharmony_ci dev_dbg(dev, "dwc3 imx8mp pm suspend.\n"); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci return ret; 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_cistatic int __maybe_unused dwc3_imx8mp_pm_resume(struct device *dev) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci struct dwc3_imx8mp *dwc3_imx = dev_get_drvdata(dev); 35562306a36Sopenharmony_ci int ret; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci if (device_may_wakeup(dwc3_imx->dev)) { 35862306a36Sopenharmony_ci disable_irq_wake(dwc3_imx->irq); 35962306a36Sopenharmony_ci } else { 36062306a36Sopenharmony_ci ret = clk_prepare_enable(dwc3_imx->suspend_clk); 36162306a36Sopenharmony_ci if (ret) 36262306a36Sopenharmony_ci return ret; 36362306a36Sopenharmony_ci } 36462306a36Sopenharmony_ci 36562306a36Sopenharmony_ci ret = clk_prepare_enable(dwc3_imx->hsio_clk); 36662306a36Sopenharmony_ci if (ret) 36762306a36Sopenharmony_ci return ret; 36862306a36Sopenharmony_ci 36962306a36Sopenharmony_ci ret = dwc3_imx8mp_resume(dwc3_imx, PMSG_RESUME); 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci pm_runtime_disable(dev); 37262306a36Sopenharmony_ci pm_runtime_set_active(dev); 37362306a36Sopenharmony_ci pm_runtime_enable(dev); 37462306a36Sopenharmony_ci 37562306a36Sopenharmony_ci dev_dbg(dev, "dwc3 imx8mp pm resume.\n"); 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci return ret; 37862306a36Sopenharmony_ci} 37962306a36Sopenharmony_ci 38062306a36Sopenharmony_cistatic int __maybe_unused dwc3_imx8mp_runtime_suspend(struct device *dev) 38162306a36Sopenharmony_ci{ 38262306a36Sopenharmony_ci struct dwc3_imx8mp *dwc3_imx = dev_get_drvdata(dev); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci dev_dbg(dev, "dwc3 imx8mp runtime suspend.\n"); 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci return dwc3_imx8mp_suspend(dwc3_imx, PMSG_AUTO_SUSPEND); 38762306a36Sopenharmony_ci} 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_cistatic int __maybe_unused dwc3_imx8mp_runtime_resume(struct device *dev) 39062306a36Sopenharmony_ci{ 39162306a36Sopenharmony_ci struct dwc3_imx8mp *dwc3_imx = dev_get_drvdata(dev); 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci dev_dbg(dev, "dwc3 imx8mp runtime resume.\n"); 39462306a36Sopenharmony_ci 39562306a36Sopenharmony_ci return dwc3_imx8mp_resume(dwc3_imx, PMSG_AUTO_RESUME); 39662306a36Sopenharmony_ci} 39762306a36Sopenharmony_ci 39862306a36Sopenharmony_cistatic const struct dev_pm_ops dwc3_imx8mp_dev_pm_ops = { 39962306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(dwc3_imx8mp_pm_suspend, dwc3_imx8mp_pm_resume) 40062306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(dwc3_imx8mp_runtime_suspend, 40162306a36Sopenharmony_ci dwc3_imx8mp_runtime_resume, NULL) 40262306a36Sopenharmony_ci}; 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_cistatic const struct of_device_id dwc3_imx8mp_of_match[] = { 40562306a36Sopenharmony_ci { .compatible = "fsl,imx8mp-dwc3", }, 40662306a36Sopenharmony_ci {}, 40762306a36Sopenharmony_ci}; 40862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, dwc3_imx8mp_of_match); 40962306a36Sopenharmony_ci 41062306a36Sopenharmony_cistatic struct platform_driver dwc3_imx8mp_driver = { 41162306a36Sopenharmony_ci .probe = dwc3_imx8mp_probe, 41262306a36Sopenharmony_ci .remove_new = dwc3_imx8mp_remove, 41362306a36Sopenharmony_ci .driver = { 41462306a36Sopenharmony_ci .name = "imx8mp-dwc3", 41562306a36Sopenharmony_ci .pm = &dwc3_imx8mp_dev_pm_ops, 41662306a36Sopenharmony_ci .of_match_table = dwc3_imx8mp_of_match, 41762306a36Sopenharmony_ci }, 41862306a36Sopenharmony_ci}; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_cimodule_platform_driver(dwc3_imx8mp_driver); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ciMODULE_ALIAS("platform:imx8mp-dwc3"); 42362306a36Sopenharmony_ciMODULE_AUTHOR("jun.li@nxp.com"); 42462306a36Sopenharmony_ciMODULE_LICENSE("GPL v2"); 42562306a36Sopenharmony_ciMODULE_DESCRIPTION("DesignWare USB3 imx8mp Glue Layer"); 426