162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Inspired by dwc3-of-simple.c
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <linux/acpi.h>
862306a36Sopenharmony_ci#include <linux/io.h>
962306a36Sopenharmony_ci#include <linux/of.h>
1062306a36Sopenharmony_ci#include <linux/clk.h>
1162306a36Sopenharmony_ci#include <linux/irq.h>
1262306a36Sopenharmony_ci#include <linux/of_clk.h>
1362306a36Sopenharmony_ci#include <linux/module.h>
1462306a36Sopenharmony_ci#include <linux/kernel.h>
1562306a36Sopenharmony_ci#include <linux/extcon.h>
1662306a36Sopenharmony_ci#include <linux/interconnect.h>
1762306a36Sopenharmony_ci#include <linux/of_platform.h>
1862306a36Sopenharmony_ci#include <linux/platform_device.h>
1962306a36Sopenharmony_ci#include <linux/phy/phy.h>
2062306a36Sopenharmony_ci#include <linux/usb/of.h>
2162306a36Sopenharmony_ci#include <linux/reset.h>
2262306a36Sopenharmony_ci#include <linux/iopoll.h>
2362306a36Sopenharmony_ci#include <linux/usb/hcd.h>
2462306a36Sopenharmony_ci#include <linux/usb.h>
2562306a36Sopenharmony_ci#include "core.h"
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/* USB QSCRATCH Hardware registers */
2862306a36Sopenharmony_ci#define QSCRATCH_HS_PHY_CTRL			0x10
2962306a36Sopenharmony_ci#define UTMI_OTG_VBUS_VALID			BIT(20)
3062306a36Sopenharmony_ci#define SW_SESSVLD_SEL				BIT(28)
3162306a36Sopenharmony_ci
3262306a36Sopenharmony_ci#define QSCRATCH_SS_PHY_CTRL			0x30
3362306a36Sopenharmony_ci#define LANE0_PWR_PRESENT			BIT(24)
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci#define QSCRATCH_GENERAL_CFG			0x08
3662306a36Sopenharmony_ci#define PIPE_UTMI_CLK_SEL			BIT(0)
3762306a36Sopenharmony_ci#define PIPE3_PHYSTATUS_SW			BIT(3)
3862306a36Sopenharmony_ci#define PIPE_UTMI_CLK_DIS			BIT(8)
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci#define PWR_EVNT_IRQ_STAT_REG			0x58
4162306a36Sopenharmony_ci#define PWR_EVNT_LPM_IN_L2_MASK			BIT(4)
4262306a36Sopenharmony_ci#define PWR_EVNT_LPM_OUT_L2_MASK		BIT(5)
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_ci#define SDM845_QSCRATCH_BASE_OFFSET		0xf8800
4562306a36Sopenharmony_ci#define SDM845_QSCRATCH_SIZE			0x400
4662306a36Sopenharmony_ci#define SDM845_DWC3_CORE_SIZE			0xcd00
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci/* Interconnect path bandwidths in MBps */
4962306a36Sopenharmony_ci#define USB_MEMORY_AVG_HS_BW MBps_to_icc(240)
5062306a36Sopenharmony_ci#define USB_MEMORY_PEAK_HS_BW MBps_to_icc(700)
5162306a36Sopenharmony_ci#define USB_MEMORY_AVG_SS_BW  MBps_to_icc(1000)
5262306a36Sopenharmony_ci#define USB_MEMORY_PEAK_SS_BW MBps_to_icc(2500)
5362306a36Sopenharmony_ci#define APPS_USB_AVG_BW 0
5462306a36Sopenharmony_ci#define APPS_USB_PEAK_BW MBps_to_icc(40)
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_cistruct dwc3_acpi_pdata {
5762306a36Sopenharmony_ci	u32			qscratch_base_offset;
5862306a36Sopenharmony_ci	u32			qscratch_base_size;
5962306a36Sopenharmony_ci	u32			dwc3_core_base_size;
6062306a36Sopenharmony_ci	int			hs_phy_irq_index;
6162306a36Sopenharmony_ci	int			dp_hs_phy_irq_index;
6262306a36Sopenharmony_ci	int			dm_hs_phy_irq_index;
6362306a36Sopenharmony_ci	int			ss_phy_irq_index;
6462306a36Sopenharmony_ci	bool			is_urs;
6562306a36Sopenharmony_ci};
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_cistruct dwc3_qcom {
6862306a36Sopenharmony_ci	struct device		*dev;
6962306a36Sopenharmony_ci	void __iomem		*qscratch_base;
7062306a36Sopenharmony_ci	struct platform_device	*dwc3;
7162306a36Sopenharmony_ci	struct platform_device	*urs_usb;
7262306a36Sopenharmony_ci	struct clk		**clks;
7362306a36Sopenharmony_ci	int			num_clocks;
7462306a36Sopenharmony_ci	struct reset_control	*resets;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	int			hs_phy_irq;
7762306a36Sopenharmony_ci	int			dp_hs_phy_irq;
7862306a36Sopenharmony_ci	int			dm_hs_phy_irq;
7962306a36Sopenharmony_ci	int			ss_phy_irq;
8062306a36Sopenharmony_ci	enum usb_device_speed	usb2_speed;
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	struct extcon_dev	*edev;
8362306a36Sopenharmony_ci	struct extcon_dev	*host_edev;
8462306a36Sopenharmony_ci	struct notifier_block	vbus_nb;
8562306a36Sopenharmony_ci	struct notifier_block	host_nb;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	const struct dwc3_acpi_pdata *acpi_pdata;
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	enum usb_dr_mode	mode;
9062306a36Sopenharmony_ci	bool			is_suspended;
9162306a36Sopenharmony_ci	bool			pm_suspended;
9262306a36Sopenharmony_ci	struct icc_path		*icc_path_ddr;
9362306a36Sopenharmony_ci	struct icc_path		*icc_path_apps;
9462306a36Sopenharmony_ci};
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_cistatic inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val)
9762306a36Sopenharmony_ci{
9862306a36Sopenharmony_ci	u32 reg;
9962306a36Sopenharmony_ci
10062306a36Sopenharmony_ci	reg = readl(base + offset);
10162306a36Sopenharmony_ci	reg |= val;
10262306a36Sopenharmony_ci	writel(reg, base + offset);
10362306a36Sopenharmony_ci
10462306a36Sopenharmony_ci	/* ensure that above write is through */
10562306a36Sopenharmony_ci	readl(base + offset);
10662306a36Sopenharmony_ci}
10762306a36Sopenharmony_ci
10862306a36Sopenharmony_cistatic inline void dwc3_qcom_clrbits(void __iomem *base, u32 offset, u32 val)
10962306a36Sopenharmony_ci{
11062306a36Sopenharmony_ci	u32 reg;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	reg = readl(base + offset);
11362306a36Sopenharmony_ci	reg &= ~val;
11462306a36Sopenharmony_ci	writel(reg, base + offset);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	/* ensure that above write is through */
11762306a36Sopenharmony_ci	readl(base + offset);
11862306a36Sopenharmony_ci}
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	if (enable) {
12362306a36Sopenharmony_ci		dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL,
12462306a36Sopenharmony_ci				  LANE0_PWR_PRESENT);
12562306a36Sopenharmony_ci		dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL,
12662306a36Sopenharmony_ci				  UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
12762306a36Sopenharmony_ci	} else {
12862306a36Sopenharmony_ci		dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL,
12962306a36Sopenharmony_ci				  LANE0_PWR_PRESENT);
13062306a36Sopenharmony_ci		dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL,
13162306a36Sopenharmony_ci				  UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
13262306a36Sopenharmony_ci	}
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic int dwc3_qcom_vbus_notifier(struct notifier_block *nb,
13662306a36Sopenharmony_ci				   unsigned long event, void *ptr)
13762306a36Sopenharmony_ci{
13862306a36Sopenharmony_ci	struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, vbus_nb);
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_ci	/* enable vbus override for device mode */
14162306a36Sopenharmony_ci	dwc3_qcom_vbus_override_enable(qcom, event);
14262306a36Sopenharmony_ci	qcom->mode = event ? USB_DR_MODE_PERIPHERAL : USB_DR_MODE_HOST;
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	return NOTIFY_DONE;
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic int dwc3_qcom_host_notifier(struct notifier_block *nb,
14862306a36Sopenharmony_ci				   unsigned long event, void *ptr)
14962306a36Sopenharmony_ci{
15062306a36Sopenharmony_ci	struct dwc3_qcom *qcom = container_of(nb, struct dwc3_qcom, host_nb);
15162306a36Sopenharmony_ci
15262306a36Sopenharmony_ci	/* disable vbus override in host mode */
15362306a36Sopenharmony_ci	dwc3_qcom_vbus_override_enable(qcom, !event);
15462306a36Sopenharmony_ci	qcom->mode = event ? USB_DR_MODE_HOST : USB_DR_MODE_PERIPHERAL;
15562306a36Sopenharmony_ci
15662306a36Sopenharmony_ci	return NOTIFY_DONE;
15762306a36Sopenharmony_ci}
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_cistatic int dwc3_qcom_register_extcon(struct dwc3_qcom *qcom)
16062306a36Sopenharmony_ci{
16162306a36Sopenharmony_ci	struct device		*dev = qcom->dev;
16262306a36Sopenharmony_ci	struct extcon_dev	*host_edev;
16362306a36Sopenharmony_ci	int			ret;
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	if (!of_property_read_bool(dev->of_node, "extcon"))
16662306a36Sopenharmony_ci		return 0;
16762306a36Sopenharmony_ci
16862306a36Sopenharmony_ci	qcom->edev = extcon_get_edev_by_phandle(dev, 0);
16962306a36Sopenharmony_ci	if (IS_ERR(qcom->edev))
17062306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(qcom->edev),
17162306a36Sopenharmony_ci				     "Failed to get extcon\n");
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	qcom->vbus_nb.notifier_call = dwc3_qcom_vbus_notifier;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	qcom->host_edev = extcon_get_edev_by_phandle(dev, 1);
17662306a36Sopenharmony_ci	if (IS_ERR(qcom->host_edev))
17762306a36Sopenharmony_ci		qcom->host_edev = NULL;
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	ret = devm_extcon_register_notifier(dev, qcom->edev, EXTCON_USB,
18062306a36Sopenharmony_ci					    &qcom->vbus_nb);
18162306a36Sopenharmony_ci	if (ret < 0) {
18262306a36Sopenharmony_ci		dev_err(dev, "VBUS notifier register failed\n");
18362306a36Sopenharmony_ci		return ret;
18462306a36Sopenharmony_ci	}
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_ci	if (qcom->host_edev)
18762306a36Sopenharmony_ci		host_edev = qcom->host_edev;
18862306a36Sopenharmony_ci	else
18962306a36Sopenharmony_ci		host_edev = qcom->edev;
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci	qcom->host_nb.notifier_call = dwc3_qcom_host_notifier;
19262306a36Sopenharmony_ci	ret = devm_extcon_register_notifier(dev, host_edev, EXTCON_USB_HOST,
19362306a36Sopenharmony_ci					    &qcom->host_nb);
19462306a36Sopenharmony_ci	if (ret < 0) {
19562306a36Sopenharmony_ci		dev_err(dev, "Host notifier register failed\n");
19662306a36Sopenharmony_ci		return ret;
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci
19962306a36Sopenharmony_ci	/* Update initial VBUS override based on extcon state */
20062306a36Sopenharmony_ci	if (extcon_get_state(qcom->edev, EXTCON_USB) ||
20162306a36Sopenharmony_ci	    !extcon_get_state(host_edev, EXTCON_USB_HOST))
20262306a36Sopenharmony_ci		dwc3_qcom_vbus_notifier(&qcom->vbus_nb, true, qcom->edev);
20362306a36Sopenharmony_ci	else
20462306a36Sopenharmony_ci		dwc3_qcom_vbus_notifier(&qcom->vbus_nb, false, qcom->edev);
20562306a36Sopenharmony_ci
20662306a36Sopenharmony_ci	return 0;
20762306a36Sopenharmony_ci}
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic int dwc3_qcom_interconnect_enable(struct dwc3_qcom *qcom)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	int ret;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	ret = icc_enable(qcom->icc_path_ddr);
21462306a36Sopenharmony_ci	if (ret)
21562306a36Sopenharmony_ci		return ret;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	ret = icc_enable(qcom->icc_path_apps);
21862306a36Sopenharmony_ci	if (ret)
21962306a36Sopenharmony_ci		icc_disable(qcom->icc_path_ddr);
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	return ret;
22262306a36Sopenharmony_ci}
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_cistatic int dwc3_qcom_interconnect_disable(struct dwc3_qcom *qcom)
22562306a36Sopenharmony_ci{
22662306a36Sopenharmony_ci	int ret;
22762306a36Sopenharmony_ci
22862306a36Sopenharmony_ci	ret = icc_disable(qcom->icc_path_ddr);
22962306a36Sopenharmony_ci	if (ret)
23062306a36Sopenharmony_ci		return ret;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	ret = icc_disable(qcom->icc_path_apps);
23362306a36Sopenharmony_ci	if (ret)
23462306a36Sopenharmony_ci		icc_enable(qcom->icc_path_ddr);
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	return ret;
23762306a36Sopenharmony_ci}
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci/**
24062306a36Sopenharmony_ci * dwc3_qcom_interconnect_init() - Get interconnect path handles
24162306a36Sopenharmony_ci * and set bandwidth.
24262306a36Sopenharmony_ci * @qcom:			Pointer to the concerned usb core.
24362306a36Sopenharmony_ci *
24462306a36Sopenharmony_ci */
24562306a36Sopenharmony_cistatic int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	enum usb_device_speed max_speed;
24862306a36Sopenharmony_ci	struct device *dev = qcom->dev;
24962306a36Sopenharmony_ci	int ret;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (has_acpi_companion(dev))
25262306a36Sopenharmony_ci		return 0;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	qcom->icc_path_ddr = of_icc_get(dev, "usb-ddr");
25562306a36Sopenharmony_ci	if (IS_ERR(qcom->icc_path_ddr)) {
25662306a36Sopenharmony_ci		return dev_err_probe(dev, PTR_ERR(qcom->icc_path_ddr),
25762306a36Sopenharmony_ci				     "failed to get usb-ddr path\n");
25862306a36Sopenharmony_ci	}
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	qcom->icc_path_apps = of_icc_get(dev, "apps-usb");
26162306a36Sopenharmony_ci	if (IS_ERR(qcom->icc_path_apps)) {
26262306a36Sopenharmony_ci		ret = dev_err_probe(dev, PTR_ERR(qcom->icc_path_apps),
26362306a36Sopenharmony_ci				    "failed to get apps-usb path\n");
26462306a36Sopenharmony_ci		goto put_path_ddr;
26562306a36Sopenharmony_ci	}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	max_speed = usb_get_maximum_speed(&qcom->dwc3->dev);
26862306a36Sopenharmony_ci	if (max_speed >= USB_SPEED_SUPER || max_speed == USB_SPEED_UNKNOWN) {
26962306a36Sopenharmony_ci		ret = icc_set_bw(qcom->icc_path_ddr,
27062306a36Sopenharmony_ci				USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW);
27162306a36Sopenharmony_ci	} else {
27262306a36Sopenharmony_ci		ret = icc_set_bw(qcom->icc_path_ddr,
27362306a36Sopenharmony_ci				USB_MEMORY_AVG_HS_BW, USB_MEMORY_PEAK_HS_BW);
27462306a36Sopenharmony_ci	}
27562306a36Sopenharmony_ci	if (ret) {
27662306a36Sopenharmony_ci		dev_err(dev, "failed to set bandwidth for usb-ddr path: %d\n", ret);
27762306a36Sopenharmony_ci		goto put_path_apps;
27862306a36Sopenharmony_ci	}
27962306a36Sopenharmony_ci
28062306a36Sopenharmony_ci	ret = icc_set_bw(qcom->icc_path_apps, APPS_USB_AVG_BW, APPS_USB_PEAK_BW);
28162306a36Sopenharmony_ci	if (ret) {
28262306a36Sopenharmony_ci		dev_err(dev, "failed to set bandwidth for apps-usb path: %d\n", ret);
28362306a36Sopenharmony_ci		goto put_path_apps;
28462306a36Sopenharmony_ci	}
28562306a36Sopenharmony_ci
28662306a36Sopenharmony_ci	return 0;
28762306a36Sopenharmony_ci
28862306a36Sopenharmony_ciput_path_apps:
28962306a36Sopenharmony_ci	icc_put(qcom->icc_path_apps);
29062306a36Sopenharmony_ciput_path_ddr:
29162306a36Sopenharmony_ci	icc_put(qcom->icc_path_ddr);
29262306a36Sopenharmony_ci	return ret;
29362306a36Sopenharmony_ci}
29462306a36Sopenharmony_ci
29562306a36Sopenharmony_ci/**
29662306a36Sopenharmony_ci * dwc3_qcom_interconnect_exit() - Release interconnect path handles
29762306a36Sopenharmony_ci * @qcom:			Pointer to the concerned usb core.
29862306a36Sopenharmony_ci *
29962306a36Sopenharmony_ci * This function is used to release interconnect path handle.
30062306a36Sopenharmony_ci */
30162306a36Sopenharmony_cistatic void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
30262306a36Sopenharmony_ci{
30362306a36Sopenharmony_ci	icc_put(qcom->icc_path_ddr);
30462306a36Sopenharmony_ci	icc_put(qcom->icc_path_apps);
30562306a36Sopenharmony_ci}
30662306a36Sopenharmony_ci
30762306a36Sopenharmony_ci/* Only usable in contexts where the role can not change. */
30862306a36Sopenharmony_cistatic bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci	struct dwc3 *dwc;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	/*
31362306a36Sopenharmony_ci	 * FIXME: Fix this layering violation.
31462306a36Sopenharmony_ci	 */
31562306a36Sopenharmony_ci	dwc = platform_get_drvdata(qcom->dwc3);
31662306a36Sopenharmony_ci
31762306a36Sopenharmony_ci	/* Core driver may not have probed yet. */
31862306a36Sopenharmony_ci	if (!dwc)
31962306a36Sopenharmony_ci		return false;
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ci	return dwc->xhci;
32262306a36Sopenharmony_ci}
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_cistatic enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom)
32562306a36Sopenharmony_ci{
32662306a36Sopenharmony_ci	struct dwc3 *dwc = platform_get_drvdata(qcom->dwc3);
32762306a36Sopenharmony_ci	struct usb_device *udev;
32862306a36Sopenharmony_ci	struct usb_hcd __maybe_unused *hcd;
32962306a36Sopenharmony_ci
33062306a36Sopenharmony_ci	/*
33162306a36Sopenharmony_ci	 * FIXME: Fix this layering violation.
33262306a36Sopenharmony_ci	 */
33362306a36Sopenharmony_ci	hcd = platform_get_drvdata(dwc->xhci);
33462306a36Sopenharmony_ci
33562306a36Sopenharmony_ci	/*
33662306a36Sopenharmony_ci	 * It is possible to query the speed of all children of
33762306a36Sopenharmony_ci	 * USB2.0 root hub via usb_hub_for_each_child(). DWC3 code
33862306a36Sopenharmony_ci	 * currently supports only 1 port per controller. So
33962306a36Sopenharmony_ci	 * this is sufficient.
34062306a36Sopenharmony_ci	 */
34162306a36Sopenharmony_ci#ifdef CONFIG_USB
34262306a36Sopenharmony_ci	udev = usb_hub_find_child(hcd->self.root_hub, 1);
34362306a36Sopenharmony_ci#else
34462306a36Sopenharmony_ci	udev = NULL;
34562306a36Sopenharmony_ci#endif
34662306a36Sopenharmony_ci	if (!udev)
34762306a36Sopenharmony_ci		return USB_SPEED_UNKNOWN;
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci	return udev->speed;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_cistatic void dwc3_qcom_enable_wakeup_irq(int irq, unsigned int polarity)
35362306a36Sopenharmony_ci{
35462306a36Sopenharmony_ci	if (!irq)
35562306a36Sopenharmony_ci		return;
35662306a36Sopenharmony_ci
35762306a36Sopenharmony_ci	if (polarity)
35862306a36Sopenharmony_ci		irq_set_irq_type(irq, polarity);
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci	enable_irq(irq);
36162306a36Sopenharmony_ci	enable_irq_wake(irq);
36262306a36Sopenharmony_ci}
36362306a36Sopenharmony_ci
36462306a36Sopenharmony_cistatic void dwc3_qcom_disable_wakeup_irq(int irq)
36562306a36Sopenharmony_ci{
36662306a36Sopenharmony_ci	if (!irq)
36762306a36Sopenharmony_ci		return;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	disable_irq_wake(irq);
37062306a36Sopenharmony_ci	disable_irq_nosync(irq);
37162306a36Sopenharmony_ci}
37262306a36Sopenharmony_ci
37362306a36Sopenharmony_cistatic void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
37462306a36Sopenharmony_ci{
37562306a36Sopenharmony_ci	dwc3_qcom_disable_wakeup_irq(qcom->hs_phy_irq);
37662306a36Sopenharmony_ci
37762306a36Sopenharmony_ci	if (qcom->usb2_speed == USB_SPEED_LOW) {
37862306a36Sopenharmony_ci		dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
37962306a36Sopenharmony_ci	} else if ((qcom->usb2_speed == USB_SPEED_HIGH) ||
38062306a36Sopenharmony_ci			(qcom->usb2_speed == USB_SPEED_FULL)) {
38162306a36Sopenharmony_ci		dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq);
38262306a36Sopenharmony_ci	} else {
38362306a36Sopenharmony_ci		dwc3_qcom_disable_wakeup_irq(qcom->dp_hs_phy_irq);
38462306a36Sopenharmony_ci		dwc3_qcom_disable_wakeup_irq(qcom->dm_hs_phy_irq);
38562306a36Sopenharmony_ci	}
38662306a36Sopenharmony_ci
38762306a36Sopenharmony_ci	dwc3_qcom_disable_wakeup_irq(qcom->ss_phy_irq);
38862306a36Sopenharmony_ci}
38962306a36Sopenharmony_ci
39062306a36Sopenharmony_cistatic void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
39162306a36Sopenharmony_ci{
39262306a36Sopenharmony_ci	dwc3_qcom_enable_wakeup_irq(qcom->hs_phy_irq, 0);
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci	/*
39562306a36Sopenharmony_ci	 * Configure DP/DM line interrupts based on the USB2 device attached to
39662306a36Sopenharmony_ci	 * the root hub port. When HS/FS device is connected, configure the DP line
39762306a36Sopenharmony_ci	 * as falling edge to detect both disconnect and remote wakeup scenarios. When
39862306a36Sopenharmony_ci	 * LS device is connected, configure DM line as falling edge to detect both
39962306a36Sopenharmony_ci	 * disconnect and remote wakeup. When no device is connected, configure both
40062306a36Sopenharmony_ci	 * DP and DM lines as rising edge to detect HS/HS/LS device connect scenario.
40162306a36Sopenharmony_ci	 */
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci	if (qcom->usb2_speed == USB_SPEED_LOW) {
40462306a36Sopenharmony_ci		dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq,
40562306a36Sopenharmony_ci						IRQ_TYPE_EDGE_FALLING);
40662306a36Sopenharmony_ci	} else if ((qcom->usb2_speed == USB_SPEED_HIGH) ||
40762306a36Sopenharmony_ci			(qcom->usb2_speed == USB_SPEED_FULL)) {
40862306a36Sopenharmony_ci		dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq,
40962306a36Sopenharmony_ci						IRQ_TYPE_EDGE_FALLING);
41062306a36Sopenharmony_ci	} else {
41162306a36Sopenharmony_ci		dwc3_qcom_enable_wakeup_irq(qcom->dp_hs_phy_irq,
41262306a36Sopenharmony_ci						IRQ_TYPE_EDGE_RISING);
41362306a36Sopenharmony_ci		dwc3_qcom_enable_wakeup_irq(qcom->dm_hs_phy_irq,
41462306a36Sopenharmony_ci						IRQ_TYPE_EDGE_RISING);
41562306a36Sopenharmony_ci	}
41662306a36Sopenharmony_ci
41762306a36Sopenharmony_ci	dwc3_qcom_enable_wakeup_irq(qcom->ss_phy_irq, 0);
41862306a36Sopenharmony_ci}
41962306a36Sopenharmony_ci
42062306a36Sopenharmony_cistatic int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
42162306a36Sopenharmony_ci{
42262306a36Sopenharmony_ci	u32 val;
42362306a36Sopenharmony_ci	int i, ret;
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_ci	if (qcom->is_suspended)
42662306a36Sopenharmony_ci		return 0;
42762306a36Sopenharmony_ci
42862306a36Sopenharmony_ci	val = readl(qcom->qscratch_base + PWR_EVNT_IRQ_STAT_REG);
42962306a36Sopenharmony_ci	if (!(val & PWR_EVNT_LPM_IN_L2_MASK))
43062306a36Sopenharmony_ci		dev_err(qcom->dev, "HS-PHY not in L2\n");
43162306a36Sopenharmony_ci
43262306a36Sopenharmony_ci	for (i = qcom->num_clocks - 1; i >= 0; i--)
43362306a36Sopenharmony_ci		clk_disable_unprepare(qcom->clks[i]);
43462306a36Sopenharmony_ci
43562306a36Sopenharmony_ci	ret = dwc3_qcom_interconnect_disable(qcom);
43662306a36Sopenharmony_ci	if (ret)
43762306a36Sopenharmony_ci		dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
43862306a36Sopenharmony_ci
43962306a36Sopenharmony_ci	/*
44062306a36Sopenharmony_ci	 * The role is stable during suspend as role switching is done from a
44162306a36Sopenharmony_ci	 * freezable workqueue.
44262306a36Sopenharmony_ci	 */
44362306a36Sopenharmony_ci	if (dwc3_qcom_is_host(qcom) && wakeup) {
44462306a36Sopenharmony_ci		qcom->usb2_speed = dwc3_qcom_read_usb2_speed(qcom);
44562306a36Sopenharmony_ci		dwc3_qcom_enable_interrupts(qcom);
44662306a36Sopenharmony_ci	}
44762306a36Sopenharmony_ci
44862306a36Sopenharmony_ci	qcom->is_suspended = true;
44962306a36Sopenharmony_ci
45062306a36Sopenharmony_ci	return 0;
45162306a36Sopenharmony_ci}
45262306a36Sopenharmony_ci
45362306a36Sopenharmony_cistatic int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup)
45462306a36Sopenharmony_ci{
45562306a36Sopenharmony_ci	int ret;
45662306a36Sopenharmony_ci	int i;
45762306a36Sopenharmony_ci
45862306a36Sopenharmony_ci	if (!qcom->is_suspended)
45962306a36Sopenharmony_ci		return 0;
46062306a36Sopenharmony_ci
46162306a36Sopenharmony_ci	if (dwc3_qcom_is_host(qcom) && wakeup)
46262306a36Sopenharmony_ci		dwc3_qcom_disable_interrupts(qcom);
46362306a36Sopenharmony_ci
46462306a36Sopenharmony_ci	for (i = 0; i < qcom->num_clocks; i++) {
46562306a36Sopenharmony_ci		ret = clk_prepare_enable(qcom->clks[i]);
46662306a36Sopenharmony_ci		if (ret < 0) {
46762306a36Sopenharmony_ci			while (--i >= 0)
46862306a36Sopenharmony_ci				clk_disable_unprepare(qcom->clks[i]);
46962306a36Sopenharmony_ci			return ret;
47062306a36Sopenharmony_ci		}
47162306a36Sopenharmony_ci	}
47262306a36Sopenharmony_ci
47362306a36Sopenharmony_ci	ret = dwc3_qcom_interconnect_enable(qcom);
47462306a36Sopenharmony_ci	if (ret)
47562306a36Sopenharmony_ci		dev_warn(qcom->dev, "failed to enable interconnect: %d\n", ret);
47662306a36Sopenharmony_ci
47762306a36Sopenharmony_ci	/* Clear existing events from PHY related to L2 in/out */
47862306a36Sopenharmony_ci	dwc3_qcom_setbits(qcom->qscratch_base, PWR_EVNT_IRQ_STAT_REG,
47962306a36Sopenharmony_ci			  PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK);
48062306a36Sopenharmony_ci
48162306a36Sopenharmony_ci	qcom->is_suspended = false;
48262306a36Sopenharmony_ci
48362306a36Sopenharmony_ci	return 0;
48462306a36Sopenharmony_ci}
48562306a36Sopenharmony_ci
48662306a36Sopenharmony_cistatic irqreturn_t qcom_dwc3_resume_irq(int irq, void *data)
48762306a36Sopenharmony_ci{
48862306a36Sopenharmony_ci	struct dwc3_qcom *qcom = data;
48962306a36Sopenharmony_ci	struct dwc3	*dwc = platform_get_drvdata(qcom->dwc3);
49062306a36Sopenharmony_ci
49162306a36Sopenharmony_ci	/* If pm_suspended then let pm_resume take care of resuming h/w */
49262306a36Sopenharmony_ci	if (qcom->pm_suspended)
49362306a36Sopenharmony_ci		return IRQ_HANDLED;
49462306a36Sopenharmony_ci
49562306a36Sopenharmony_ci	/*
49662306a36Sopenharmony_ci	 * This is safe as role switching is done from a freezable workqueue
49762306a36Sopenharmony_ci	 * and the wakeup interrupts are disabled as part of resume.
49862306a36Sopenharmony_ci	 */
49962306a36Sopenharmony_ci	if (dwc3_qcom_is_host(qcom))
50062306a36Sopenharmony_ci		pm_runtime_resume(&dwc->xhci->dev);
50162306a36Sopenharmony_ci
50262306a36Sopenharmony_ci	return IRQ_HANDLED;
50362306a36Sopenharmony_ci}
50462306a36Sopenharmony_ci
50562306a36Sopenharmony_cistatic void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom)
50662306a36Sopenharmony_ci{
50762306a36Sopenharmony_ci	/* Configure dwc3 to use UTMI clock as PIPE clock not present */
50862306a36Sopenharmony_ci	dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
50962306a36Sopenharmony_ci			  PIPE_UTMI_CLK_DIS);
51062306a36Sopenharmony_ci
51162306a36Sopenharmony_ci	usleep_range(100, 1000);
51262306a36Sopenharmony_ci
51362306a36Sopenharmony_ci	dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
51462306a36Sopenharmony_ci			  PIPE_UTMI_CLK_SEL | PIPE3_PHYSTATUS_SW);
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci	usleep_range(100, 1000);
51762306a36Sopenharmony_ci
51862306a36Sopenharmony_ci	dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
51962306a36Sopenharmony_ci			  PIPE_UTMI_CLK_DIS);
52062306a36Sopenharmony_ci}
52162306a36Sopenharmony_ci
52262306a36Sopenharmony_cistatic int dwc3_qcom_get_irq(struct platform_device *pdev,
52362306a36Sopenharmony_ci			     const char *name, int num)
52462306a36Sopenharmony_ci{
52562306a36Sopenharmony_ci	struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
52662306a36Sopenharmony_ci	struct platform_device *pdev_irq = qcom->urs_usb ? qcom->urs_usb : pdev;
52762306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
52862306a36Sopenharmony_ci	int ret;
52962306a36Sopenharmony_ci
53062306a36Sopenharmony_ci	if (np)
53162306a36Sopenharmony_ci		ret = platform_get_irq_byname_optional(pdev_irq, name);
53262306a36Sopenharmony_ci	else
53362306a36Sopenharmony_ci		ret = platform_get_irq_optional(pdev_irq, num);
53462306a36Sopenharmony_ci
53562306a36Sopenharmony_ci	return ret;
53662306a36Sopenharmony_ci}
53762306a36Sopenharmony_ci
53862306a36Sopenharmony_cistatic int dwc3_qcom_setup_irq(struct platform_device *pdev)
53962306a36Sopenharmony_ci{
54062306a36Sopenharmony_ci	struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
54162306a36Sopenharmony_ci	const struct dwc3_acpi_pdata *pdata = qcom->acpi_pdata;
54262306a36Sopenharmony_ci	int irq;
54362306a36Sopenharmony_ci	int ret;
54462306a36Sopenharmony_ci
54562306a36Sopenharmony_ci	irq = dwc3_qcom_get_irq(pdev, "hs_phy_irq",
54662306a36Sopenharmony_ci				pdata ? pdata->hs_phy_irq_index : -1);
54762306a36Sopenharmony_ci	if (irq > 0) {
54862306a36Sopenharmony_ci		/* Keep wakeup interrupts disabled until suspend */
54962306a36Sopenharmony_ci		irq_set_status_flags(irq, IRQ_NOAUTOEN);
55062306a36Sopenharmony_ci		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
55162306a36Sopenharmony_ci					qcom_dwc3_resume_irq,
55262306a36Sopenharmony_ci					IRQF_ONESHOT,
55362306a36Sopenharmony_ci					"qcom_dwc3 HS", qcom);
55462306a36Sopenharmony_ci		if (ret) {
55562306a36Sopenharmony_ci			dev_err(qcom->dev, "hs_phy_irq failed: %d\n", ret);
55662306a36Sopenharmony_ci			return ret;
55762306a36Sopenharmony_ci		}
55862306a36Sopenharmony_ci		qcom->hs_phy_irq = irq;
55962306a36Sopenharmony_ci	}
56062306a36Sopenharmony_ci
56162306a36Sopenharmony_ci	irq = dwc3_qcom_get_irq(pdev, "dp_hs_phy_irq",
56262306a36Sopenharmony_ci				pdata ? pdata->dp_hs_phy_irq_index : -1);
56362306a36Sopenharmony_ci	if (irq > 0) {
56462306a36Sopenharmony_ci		irq_set_status_flags(irq, IRQ_NOAUTOEN);
56562306a36Sopenharmony_ci		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
56662306a36Sopenharmony_ci					qcom_dwc3_resume_irq,
56762306a36Sopenharmony_ci					IRQF_ONESHOT,
56862306a36Sopenharmony_ci					"qcom_dwc3 DP_HS", qcom);
56962306a36Sopenharmony_ci		if (ret) {
57062306a36Sopenharmony_ci			dev_err(qcom->dev, "dp_hs_phy_irq failed: %d\n", ret);
57162306a36Sopenharmony_ci			return ret;
57262306a36Sopenharmony_ci		}
57362306a36Sopenharmony_ci		qcom->dp_hs_phy_irq = irq;
57462306a36Sopenharmony_ci	}
57562306a36Sopenharmony_ci
57662306a36Sopenharmony_ci	irq = dwc3_qcom_get_irq(pdev, "dm_hs_phy_irq",
57762306a36Sopenharmony_ci				pdata ? pdata->dm_hs_phy_irq_index : -1);
57862306a36Sopenharmony_ci	if (irq > 0) {
57962306a36Sopenharmony_ci		irq_set_status_flags(irq, IRQ_NOAUTOEN);
58062306a36Sopenharmony_ci		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
58162306a36Sopenharmony_ci					qcom_dwc3_resume_irq,
58262306a36Sopenharmony_ci					IRQF_ONESHOT,
58362306a36Sopenharmony_ci					"qcom_dwc3 DM_HS", qcom);
58462306a36Sopenharmony_ci		if (ret) {
58562306a36Sopenharmony_ci			dev_err(qcom->dev, "dm_hs_phy_irq failed: %d\n", ret);
58662306a36Sopenharmony_ci			return ret;
58762306a36Sopenharmony_ci		}
58862306a36Sopenharmony_ci		qcom->dm_hs_phy_irq = irq;
58962306a36Sopenharmony_ci	}
59062306a36Sopenharmony_ci
59162306a36Sopenharmony_ci	irq = dwc3_qcom_get_irq(pdev, "ss_phy_irq",
59262306a36Sopenharmony_ci				pdata ? pdata->ss_phy_irq_index : -1);
59362306a36Sopenharmony_ci	if (irq > 0) {
59462306a36Sopenharmony_ci		irq_set_status_flags(irq, IRQ_NOAUTOEN);
59562306a36Sopenharmony_ci		ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
59662306a36Sopenharmony_ci					qcom_dwc3_resume_irq,
59762306a36Sopenharmony_ci					IRQF_ONESHOT,
59862306a36Sopenharmony_ci					"qcom_dwc3 SS", qcom);
59962306a36Sopenharmony_ci		if (ret) {
60062306a36Sopenharmony_ci			dev_err(qcom->dev, "ss_phy_irq failed: %d\n", ret);
60162306a36Sopenharmony_ci			return ret;
60262306a36Sopenharmony_ci		}
60362306a36Sopenharmony_ci		qcom->ss_phy_irq = irq;
60462306a36Sopenharmony_ci	}
60562306a36Sopenharmony_ci
60662306a36Sopenharmony_ci	return 0;
60762306a36Sopenharmony_ci}
60862306a36Sopenharmony_ci
60962306a36Sopenharmony_cistatic int dwc3_qcom_clk_init(struct dwc3_qcom *qcom, int count)
61062306a36Sopenharmony_ci{
61162306a36Sopenharmony_ci	struct device		*dev = qcom->dev;
61262306a36Sopenharmony_ci	struct device_node	*np = dev->of_node;
61362306a36Sopenharmony_ci	int			i;
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (!np || !count)
61662306a36Sopenharmony_ci		return 0;
61762306a36Sopenharmony_ci
61862306a36Sopenharmony_ci	if (count < 0)
61962306a36Sopenharmony_ci		return count;
62062306a36Sopenharmony_ci
62162306a36Sopenharmony_ci	qcom->num_clocks = count;
62262306a36Sopenharmony_ci
62362306a36Sopenharmony_ci	qcom->clks = devm_kcalloc(dev, qcom->num_clocks,
62462306a36Sopenharmony_ci				  sizeof(struct clk *), GFP_KERNEL);
62562306a36Sopenharmony_ci	if (!qcom->clks)
62662306a36Sopenharmony_ci		return -ENOMEM;
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	for (i = 0; i < qcom->num_clocks; i++) {
62962306a36Sopenharmony_ci		struct clk	*clk;
63062306a36Sopenharmony_ci		int		ret;
63162306a36Sopenharmony_ci
63262306a36Sopenharmony_ci		clk = of_clk_get(np, i);
63362306a36Sopenharmony_ci		if (IS_ERR(clk)) {
63462306a36Sopenharmony_ci			while (--i >= 0)
63562306a36Sopenharmony_ci				clk_put(qcom->clks[i]);
63662306a36Sopenharmony_ci			return PTR_ERR(clk);
63762306a36Sopenharmony_ci		}
63862306a36Sopenharmony_ci
63962306a36Sopenharmony_ci		ret = clk_prepare_enable(clk);
64062306a36Sopenharmony_ci		if (ret < 0) {
64162306a36Sopenharmony_ci			while (--i >= 0) {
64262306a36Sopenharmony_ci				clk_disable_unprepare(qcom->clks[i]);
64362306a36Sopenharmony_ci				clk_put(qcom->clks[i]);
64462306a36Sopenharmony_ci			}
64562306a36Sopenharmony_ci			clk_put(clk);
64662306a36Sopenharmony_ci
64762306a36Sopenharmony_ci			return ret;
64862306a36Sopenharmony_ci		}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci		qcom->clks[i] = clk;
65162306a36Sopenharmony_ci	}
65262306a36Sopenharmony_ci
65362306a36Sopenharmony_ci	return 0;
65462306a36Sopenharmony_ci}
65562306a36Sopenharmony_ci
65662306a36Sopenharmony_cistatic const struct property_entry dwc3_qcom_acpi_properties[] = {
65762306a36Sopenharmony_ci	PROPERTY_ENTRY_STRING("dr_mode", "host"),
65862306a36Sopenharmony_ci	{}
65962306a36Sopenharmony_ci};
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_cistatic const struct software_node dwc3_qcom_swnode = {
66262306a36Sopenharmony_ci	.properties = dwc3_qcom_acpi_properties,
66362306a36Sopenharmony_ci};
66462306a36Sopenharmony_ci
66562306a36Sopenharmony_cistatic int dwc3_qcom_acpi_register_core(struct platform_device *pdev)
66662306a36Sopenharmony_ci{
66762306a36Sopenharmony_ci	struct dwc3_qcom	*qcom = platform_get_drvdata(pdev);
66862306a36Sopenharmony_ci	struct device		*dev = &pdev->dev;
66962306a36Sopenharmony_ci	struct resource		*res, *child_res = NULL;
67062306a36Sopenharmony_ci	struct platform_device	*pdev_irq = qcom->urs_usb ? qcom->urs_usb :
67162306a36Sopenharmony_ci							    pdev;
67262306a36Sopenharmony_ci	int			irq;
67362306a36Sopenharmony_ci	int			ret;
67462306a36Sopenharmony_ci
67562306a36Sopenharmony_ci	qcom->dwc3 = platform_device_alloc("dwc3", PLATFORM_DEVID_AUTO);
67662306a36Sopenharmony_ci	if (!qcom->dwc3)
67762306a36Sopenharmony_ci		return -ENOMEM;
67862306a36Sopenharmony_ci
67962306a36Sopenharmony_ci	qcom->dwc3->dev.parent = dev;
68062306a36Sopenharmony_ci	qcom->dwc3->dev.type = dev->type;
68162306a36Sopenharmony_ci	qcom->dwc3->dev.dma_mask = dev->dma_mask;
68262306a36Sopenharmony_ci	qcom->dwc3->dev.dma_parms = dev->dma_parms;
68362306a36Sopenharmony_ci	qcom->dwc3->dev.coherent_dma_mask = dev->coherent_dma_mask;
68462306a36Sopenharmony_ci
68562306a36Sopenharmony_ci	child_res = kcalloc(2, sizeof(*child_res), GFP_KERNEL);
68662306a36Sopenharmony_ci	if (!child_res) {
68762306a36Sopenharmony_ci		platform_device_put(qcom->dwc3);
68862306a36Sopenharmony_ci		return -ENOMEM;
68962306a36Sopenharmony_ci	}
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
69262306a36Sopenharmony_ci	if (!res) {
69362306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to get memory resource\n");
69462306a36Sopenharmony_ci		ret = -ENODEV;
69562306a36Sopenharmony_ci		goto out;
69662306a36Sopenharmony_ci	}
69762306a36Sopenharmony_ci
69862306a36Sopenharmony_ci	child_res[0].flags = res->flags;
69962306a36Sopenharmony_ci	child_res[0].start = res->start;
70062306a36Sopenharmony_ci	child_res[0].end = child_res[0].start +
70162306a36Sopenharmony_ci		qcom->acpi_pdata->dwc3_core_base_size;
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	irq = platform_get_irq(pdev_irq, 0);
70462306a36Sopenharmony_ci	if (irq < 0) {
70562306a36Sopenharmony_ci		ret = irq;
70662306a36Sopenharmony_ci		goto out;
70762306a36Sopenharmony_ci	}
70862306a36Sopenharmony_ci	child_res[1].flags = IORESOURCE_IRQ;
70962306a36Sopenharmony_ci	child_res[1].start = child_res[1].end = irq;
71062306a36Sopenharmony_ci
71162306a36Sopenharmony_ci	ret = platform_device_add_resources(qcom->dwc3, child_res, 2);
71262306a36Sopenharmony_ci	if (ret) {
71362306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to add resources\n");
71462306a36Sopenharmony_ci		goto out;
71562306a36Sopenharmony_ci	}
71662306a36Sopenharmony_ci
71762306a36Sopenharmony_ci	ret = device_add_software_node(&qcom->dwc3->dev, &dwc3_qcom_swnode);
71862306a36Sopenharmony_ci	if (ret < 0) {
71962306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to add properties\n");
72062306a36Sopenharmony_ci		goto out;
72162306a36Sopenharmony_ci	}
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	ret = platform_device_add(qcom->dwc3);
72462306a36Sopenharmony_ci	if (ret) {
72562306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to add device\n");
72662306a36Sopenharmony_ci		device_remove_software_node(&qcom->dwc3->dev);
72762306a36Sopenharmony_ci		goto out;
72862306a36Sopenharmony_ci	}
72962306a36Sopenharmony_ci	kfree(child_res);
73062306a36Sopenharmony_ci	return 0;
73162306a36Sopenharmony_ci
73262306a36Sopenharmony_ciout:
73362306a36Sopenharmony_ci	platform_device_put(qcom->dwc3);
73462306a36Sopenharmony_ci	kfree(child_res);
73562306a36Sopenharmony_ci	return ret;
73662306a36Sopenharmony_ci}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_cistatic int dwc3_qcom_of_register_core(struct platform_device *pdev)
73962306a36Sopenharmony_ci{
74062306a36Sopenharmony_ci	struct dwc3_qcom	*qcom = platform_get_drvdata(pdev);
74162306a36Sopenharmony_ci	struct device_node	*np = pdev->dev.of_node, *dwc3_np;
74262306a36Sopenharmony_ci	struct device		*dev = &pdev->dev;
74362306a36Sopenharmony_ci	int			ret;
74462306a36Sopenharmony_ci
74562306a36Sopenharmony_ci	dwc3_np = of_get_compatible_child(np, "snps,dwc3");
74662306a36Sopenharmony_ci	if (!dwc3_np) {
74762306a36Sopenharmony_ci		dev_err(dev, "failed to find dwc3 core child\n");
74862306a36Sopenharmony_ci		return -ENODEV;
74962306a36Sopenharmony_ci	}
75062306a36Sopenharmony_ci
75162306a36Sopenharmony_ci	ret = of_platform_populate(np, NULL, NULL, dev);
75262306a36Sopenharmony_ci	if (ret) {
75362306a36Sopenharmony_ci		dev_err(dev, "failed to register dwc3 core - %d\n", ret);
75462306a36Sopenharmony_ci		goto node_put;
75562306a36Sopenharmony_ci	}
75662306a36Sopenharmony_ci
75762306a36Sopenharmony_ci	qcom->dwc3 = of_find_device_by_node(dwc3_np);
75862306a36Sopenharmony_ci	if (!qcom->dwc3) {
75962306a36Sopenharmony_ci		ret = -ENODEV;
76062306a36Sopenharmony_ci		dev_err(dev, "failed to get dwc3 platform device\n");
76162306a36Sopenharmony_ci		of_platform_depopulate(dev);
76262306a36Sopenharmony_ci	}
76362306a36Sopenharmony_ci
76462306a36Sopenharmony_cinode_put:
76562306a36Sopenharmony_ci	of_node_put(dwc3_np);
76662306a36Sopenharmony_ci
76762306a36Sopenharmony_ci	return ret;
76862306a36Sopenharmony_ci}
76962306a36Sopenharmony_ci
77062306a36Sopenharmony_cistatic struct platform_device *dwc3_qcom_create_urs_usb_platdev(struct device *dev)
77162306a36Sopenharmony_ci{
77262306a36Sopenharmony_ci	struct platform_device *urs_usb = NULL;
77362306a36Sopenharmony_ci	struct fwnode_handle *fwh;
77462306a36Sopenharmony_ci	struct acpi_device *adev;
77562306a36Sopenharmony_ci	char name[8];
77662306a36Sopenharmony_ci	int ret;
77762306a36Sopenharmony_ci	int id;
77862306a36Sopenharmony_ci
77962306a36Sopenharmony_ci	/* Figure out device id */
78062306a36Sopenharmony_ci	ret = sscanf(fwnode_get_name(dev->fwnode), "URS%d", &id);
78162306a36Sopenharmony_ci	if (!ret)
78262306a36Sopenharmony_ci		return NULL;
78362306a36Sopenharmony_ci
78462306a36Sopenharmony_ci	/* Find the child using name */
78562306a36Sopenharmony_ci	snprintf(name, sizeof(name), "USB%d", id);
78662306a36Sopenharmony_ci	fwh = fwnode_get_named_child_node(dev->fwnode, name);
78762306a36Sopenharmony_ci	if (!fwh)
78862306a36Sopenharmony_ci		return NULL;
78962306a36Sopenharmony_ci
79062306a36Sopenharmony_ci	adev = to_acpi_device_node(fwh);
79162306a36Sopenharmony_ci	if (!adev)
79262306a36Sopenharmony_ci		goto err_put_handle;
79362306a36Sopenharmony_ci
79462306a36Sopenharmony_ci	urs_usb = acpi_create_platform_device(adev, NULL);
79562306a36Sopenharmony_ci	if (IS_ERR_OR_NULL(urs_usb))
79662306a36Sopenharmony_ci		goto err_put_handle;
79762306a36Sopenharmony_ci
79862306a36Sopenharmony_ci	return urs_usb;
79962306a36Sopenharmony_ci
80062306a36Sopenharmony_cierr_put_handle:
80162306a36Sopenharmony_ci	fwnode_handle_put(fwh);
80262306a36Sopenharmony_ci
80362306a36Sopenharmony_ci	return urs_usb;
80462306a36Sopenharmony_ci}
80562306a36Sopenharmony_ci
80662306a36Sopenharmony_cistatic void dwc3_qcom_destroy_urs_usb_platdev(struct platform_device *urs_usb)
80762306a36Sopenharmony_ci{
80862306a36Sopenharmony_ci	struct fwnode_handle *fwh = urs_usb->dev.fwnode;
80962306a36Sopenharmony_ci
81062306a36Sopenharmony_ci	platform_device_unregister(urs_usb);
81162306a36Sopenharmony_ci	fwnode_handle_put(fwh);
81262306a36Sopenharmony_ci}
81362306a36Sopenharmony_ci
81462306a36Sopenharmony_cistatic int dwc3_qcom_probe(struct platform_device *pdev)
81562306a36Sopenharmony_ci{
81662306a36Sopenharmony_ci	struct device_node	*np = pdev->dev.of_node;
81762306a36Sopenharmony_ci	struct device		*dev = &pdev->dev;
81862306a36Sopenharmony_ci	struct dwc3_qcom	*qcom;
81962306a36Sopenharmony_ci	struct resource		*res, *parent_res = NULL;
82062306a36Sopenharmony_ci	struct resource		local_res;
82162306a36Sopenharmony_ci	int			ret, i;
82262306a36Sopenharmony_ci	bool			ignore_pipe_clk;
82362306a36Sopenharmony_ci	bool			wakeup_source;
82462306a36Sopenharmony_ci
82562306a36Sopenharmony_ci	qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL);
82662306a36Sopenharmony_ci	if (!qcom)
82762306a36Sopenharmony_ci		return -ENOMEM;
82862306a36Sopenharmony_ci
82962306a36Sopenharmony_ci	platform_set_drvdata(pdev, qcom);
83062306a36Sopenharmony_ci	qcom->dev = &pdev->dev;
83162306a36Sopenharmony_ci
83262306a36Sopenharmony_ci	if (has_acpi_companion(dev)) {
83362306a36Sopenharmony_ci		qcom->acpi_pdata = acpi_device_get_match_data(dev);
83462306a36Sopenharmony_ci		if (!qcom->acpi_pdata) {
83562306a36Sopenharmony_ci			dev_err(&pdev->dev, "no supporting ACPI device data\n");
83662306a36Sopenharmony_ci			return -EINVAL;
83762306a36Sopenharmony_ci		}
83862306a36Sopenharmony_ci	}
83962306a36Sopenharmony_ci
84062306a36Sopenharmony_ci	qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
84162306a36Sopenharmony_ci	if (IS_ERR(qcom->resets)) {
84262306a36Sopenharmony_ci		return dev_err_probe(&pdev->dev, PTR_ERR(qcom->resets),
84362306a36Sopenharmony_ci				     "failed to get resets\n");
84462306a36Sopenharmony_ci	}
84562306a36Sopenharmony_ci
84662306a36Sopenharmony_ci	ret = reset_control_assert(qcom->resets);
84762306a36Sopenharmony_ci	if (ret) {
84862306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to assert resets, err=%d\n", ret);
84962306a36Sopenharmony_ci		return ret;
85062306a36Sopenharmony_ci	}
85162306a36Sopenharmony_ci
85262306a36Sopenharmony_ci	usleep_range(10, 1000);
85362306a36Sopenharmony_ci
85462306a36Sopenharmony_ci	ret = reset_control_deassert(qcom->resets);
85562306a36Sopenharmony_ci	if (ret) {
85662306a36Sopenharmony_ci		dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret);
85762306a36Sopenharmony_ci		goto reset_assert;
85862306a36Sopenharmony_ci	}
85962306a36Sopenharmony_ci
86062306a36Sopenharmony_ci	ret = dwc3_qcom_clk_init(qcom, of_clk_get_parent_count(np));
86162306a36Sopenharmony_ci	if (ret) {
86262306a36Sopenharmony_ci		dev_err_probe(dev, ret, "failed to get clocks\n");
86362306a36Sopenharmony_ci		goto reset_assert;
86462306a36Sopenharmony_ci	}
86562306a36Sopenharmony_ci
86662306a36Sopenharmony_ci	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
86762306a36Sopenharmony_ci
86862306a36Sopenharmony_ci	if (np) {
86962306a36Sopenharmony_ci		parent_res = res;
87062306a36Sopenharmony_ci	} else {
87162306a36Sopenharmony_ci		memcpy(&local_res, res, sizeof(struct resource));
87262306a36Sopenharmony_ci		parent_res = &local_res;
87362306a36Sopenharmony_ci
87462306a36Sopenharmony_ci		parent_res->start = res->start +
87562306a36Sopenharmony_ci			qcom->acpi_pdata->qscratch_base_offset;
87662306a36Sopenharmony_ci		parent_res->end = parent_res->start +
87762306a36Sopenharmony_ci			qcom->acpi_pdata->qscratch_base_size;
87862306a36Sopenharmony_ci
87962306a36Sopenharmony_ci		if (qcom->acpi_pdata->is_urs) {
88062306a36Sopenharmony_ci			qcom->urs_usb = dwc3_qcom_create_urs_usb_platdev(dev);
88162306a36Sopenharmony_ci			if (IS_ERR_OR_NULL(qcom->urs_usb)) {
88262306a36Sopenharmony_ci				dev_err(dev, "failed to create URS USB platdev\n");
88362306a36Sopenharmony_ci				if (!qcom->urs_usb)
88462306a36Sopenharmony_ci					ret = -ENODEV;
88562306a36Sopenharmony_ci				else
88662306a36Sopenharmony_ci					ret = PTR_ERR(qcom->urs_usb);
88762306a36Sopenharmony_ci				goto clk_disable;
88862306a36Sopenharmony_ci			}
88962306a36Sopenharmony_ci		}
89062306a36Sopenharmony_ci	}
89162306a36Sopenharmony_ci
89262306a36Sopenharmony_ci	qcom->qscratch_base = devm_ioremap_resource(dev, parent_res);
89362306a36Sopenharmony_ci	if (IS_ERR(qcom->qscratch_base)) {
89462306a36Sopenharmony_ci		ret = PTR_ERR(qcom->qscratch_base);
89562306a36Sopenharmony_ci		goto free_urs;
89662306a36Sopenharmony_ci	}
89762306a36Sopenharmony_ci
89862306a36Sopenharmony_ci	ret = dwc3_qcom_setup_irq(pdev);
89962306a36Sopenharmony_ci	if (ret) {
90062306a36Sopenharmony_ci		dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
90162306a36Sopenharmony_ci		goto free_urs;
90262306a36Sopenharmony_ci	}
90362306a36Sopenharmony_ci
90462306a36Sopenharmony_ci	/*
90562306a36Sopenharmony_ci	 * Disable pipe_clk requirement if specified. Used when dwc3
90662306a36Sopenharmony_ci	 * operates without SSPHY and only HS/FS/LS modes are supported.
90762306a36Sopenharmony_ci	 */
90862306a36Sopenharmony_ci	ignore_pipe_clk = device_property_read_bool(dev,
90962306a36Sopenharmony_ci				"qcom,select-utmi-as-pipe-clk");
91062306a36Sopenharmony_ci	if (ignore_pipe_clk)
91162306a36Sopenharmony_ci		dwc3_qcom_select_utmi_clk(qcom);
91262306a36Sopenharmony_ci
91362306a36Sopenharmony_ci	if (np)
91462306a36Sopenharmony_ci		ret = dwc3_qcom_of_register_core(pdev);
91562306a36Sopenharmony_ci	else
91662306a36Sopenharmony_ci		ret = dwc3_qcom_acpi_register_core(pdev);
91762306a36Sopenharmony_ci
91862306a36Sopenharmony_ci	if (ret) {
91962306a36Sopenharmony_ci		dev_err(dev, "failed to register DWC3 Core, err=%d\n", ret);
92062306a36Sopenharmony_ci		goto free_urs;
92162306a36Sopenharmony_ci	}
92262306a36Sopenharmony_ci
92362306a36Sopenharmony_ci	ret = dwc3_qcom_interconnect_init(qcom);
92462306a36Sopenharmony_ci	if (ret)
92562306a36Sopenharmony_ci		goto depopulate;
92662306a36Sopenharmony_ci
92762306a36Sopenharmony_ci	qcom->mode = usb_get_dr_mode(&qcom->dwc3->dev);
92862306a36Sopenharmony_ci
92962306a36Sopenharmony_ci	/* enable vbus override for device mode */
93062306a36Sopenharmony_ci	if (qcom->mode != USB_DR_MODE_HOST)
93162306a36Sopenharmony_ci		dwc3_qcom_vbus_override_enable(qcom, true);
93262306a36Sopenharmony_ci
93362306a36Sopenharmony_ci	/* register extcon to override sw_vbus on Vbus change later */
93462306a36Sopenharmony_ci	ret = dwc3_qcom_register_extcon(qcom);
93562306a36Sopenharmony_ci	if (ret)
93662306a36Sopenharmony_ci		goto interconnect_exit;
93762306a36Sopenharmony_ci
93862306a36Sopenharmony_ci	wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source");
93962306a36Sopenharmony_ci	device_init_wakeup(&pdev->dev, wakeup_source);
94062306a36Sopenharmony_ci	device_init_wakeup(&qcom->dwc3->dev, wakeup_source);
94162306a36Sopenharmony_ci
94262306a36Sopenharmony_ci	qcom->is_suspended = false;
94362306a36Sopenharmony_ci	pm_runtime_set_active(dev);
94462306a36Sopenharmony_ci	pm_runtime_enable(dev);
94562306a36Sopenharmony_ci	pm_runtime_forbid(dev);
94662306a36Sopenharmony_ci
94762306a36Sopenharmony_ci	return 0;
94862306a36Sopenharmony_ci
94962306a36Sopenharmony_ciinterconnect_exit:
95062306a36Sopenharmony_ci	dwc3_qcom_interconnect_exit(qcom);
95162306a36Sopenharmony_cidepopulate:
95262306a36Sopenharmony_ci	if (np) {
95362306a36Sopenharmony_ci		of_platform_depopulate(&pdev->dev);
95462306a36Sopenharmony_ci	} else {
95562306a36Sopenharmony_ci		device_remove_software_node(&qcom->dwc3->dev);
95662306a36Sopenharmony_ci		platform_device_del(qcom->dwc3);
95762306a36Sopenharmony_ci	}
95862306a36Sopenharmony_ci	platform_device_put(qcom->dwc3);
95962306a36Sopenharmony_cifree_urs:
96062306a36Sopenharmony_ci	if (qcom->urs_usb)
96162306a36Sopenharmony_ci		dwc3_qcom_destroy_urs_usb_platdev(qcom->urs_usb);
96262306a36Sopenharmony_ciclk_disable:
96362306a36Sopenharmony_ci	for (i = qcom->num_clocks - 1; i >= 0; i--) {
96462306a36Sopenharmony_ci		clk_disable_unprepare(qcom->clks[i]);
96562306a36Sopenharmony_ci		clk_put(qcom->clks[i]);
96662306a36Sopenharmony_ci	}
96762306a36Sopenharmony_cireset_assert:
96862306a36Sopenharmony_ci	reset_control_assert(qcom->resets);
96962306a36Sopenharmony_ci
97062306a36Sopenharmony_ci	return ret;
97162306a36Sopenharmony_ci}
97262306a36Sopenharmony_ci
97362306a36Sopenharmony_cistatic void dwc3_qcom_remove(struct platform_device *pdev)
97462306a36Sopenharmony_ci{
97562306a36Sopenharmony_ci	struct dwc3_qcom *qcom = platform_get_drvdata(pdev);
97662306a36Sopenharmony_ci	struct device_node *np = pdev->dev.of_node;
97762306a36Sopenharmony_ci	struct device *dev = &pdev->dev;
97862306a36Sopenharmony_ci	int i;
97962306a36Sopenharmony_ci
98062306a36Sopenharmony_ci	if (np) {
98162306a36Sopenharmony_ci		of_platform_depopulate(&pdev->dev);
98262306a36Sopenharmony_ci	} else {
98362306a36Sopenharmony_ci		device_remove_software_node(&qcom->dwc3->dev);
98462306a36Sopenharmony_ci		platform_device_del(qcom->dwc3);
98562306a36Sopenharmony_ci	}
98662306a36Sopenharmony_ci	platform_device_put(qcom->dwc3);
98762306a36Sopenharmony_ci
98862306a36Sopenharmony_ci	if (qcom->urs_usb)
98962306a36Sopenharmony_ci		dwc3_qcom_destroy_urs_usb_platdev(qcom->urs_usb);
99062306a36Sopenharmony_ci
99162306a36Sopenharmony_ci	for (i = qcom->num_clocks - 1; i >= 0; i--) {
99262306a36Sopenharmony_ci		clk_disable_unprepare(qcom->clks[i]);
99362306a36Sopenharmony_ci		clk_put(qcom->clks[i]);
99462306a36Sopenharmony_ci	}
99562306a36Sopenharmony_ci	qcom->num_clocks = 0;
99662306a36Sopenharmony_ci
99762306a36Sopenharmony_ci	dwc3_qcom_interconnect_exit(qcom);
99862306a36Sopenharmony_ci	reset_control_assert(qcom->resets);
99962306a36Sopenharmony_ci
100062306a36Sopenharmony_ci	pm_runtime_allow(dev);
100162306a36Sopenharmony_ci	pm_runtime_disable(dev);
100262306a36Sopenharmony_ci}
100362306a36Sopenharmony_ci
100462306a36Sopenharmony_cistatic int __maybe_unused dwc3_qcom_pm_suspend(struct device *dev)
100562306a36Sopenharmony_ci{
100662306a36Sopenharmony_ci	struct dwc3_qcom *qcom = dev_get_drvdata(dev);
100762306a36Sopenharmony_ci	bool wakeup = device_may_wakeup(dev);
100862306a36Sopenharmony_ci	int ret;
100962306a36Sopenharmony_ci
101062306a36Sopenharmony_ci	ret = dwc3_qcom_suspend(qcom, wakeup);
101162306a36Sopenharmony_ci	if (ret)
101262306a36Sopenharmony_ci		return ret;
101362306a36Sopenharmony_ci
101462306a36Sopenharmony_ci	qcom->pm_suspended = true;
101562306a36Sopenharmony_ci
101662306a36Sopenharmony_ci	return 0;
101762306a36Sopenharmony_ci}
101862306a36Sopenharmony_ci
101962306a36Sopenharmony_cistatic int __maybe_unused dwc3_qcom_pm_resume(struct device *dev)
102062306a36Sopenharmony_ci{
102162306a36Sopenharmony_ci	struct dwc3_qcom *qcom = dev_get_drvdata(dev);
102262306a36Sopenharmony_ci	bool wakeup = device_may_wakeup(dev);
102362306a36Sopenharmony_ci	int ret;
102462306a36Sopenharmony_ci
102562306a36Sopenharmony_ci	ret = dwc3_qcom_resume(qcom, wakeup);
102662306a36Sopenharmony_ci	if (ret)
102762306a36Sopenharmony_ci		return ret;
102862306a36Sopenharmony_ci
102962306a36Sopenharmony_ci	qcom->pm_suspended = false;
103062306a36Sopenharmony_ci
103162306a36Sopenharmony_ci	return 0;
103262306a36Sopenharmony_ci}
103362306a36Sopenharmony_ci
103462306a36Sopenharmony_cistatic int __maybe_unused dwc3_qcom_runtime_suspend(struct device *dev)
103562306a36Sopenharmony_ci{
103662306a36Sopenharmony_ci	struct dwc3_qcom *qcom = dev_get_drvdata(dev);
103762306a36Sopenharmony_ci
103862306a36Sopenharmony_ci	return dwc3_qcom_suspend(qcom, true);
103962306a36Sopenharmony_ci}
104062306a36Sopenharmony_ci
104162306a36Sopenharmony_cistatic int __maybe_unused dwc3_qcom_runtime_resume(struct device *dev)
104262306a36Sopenharmony_ci{
104362306a36Sopenharmony_ci	struct dwc3_qcom *qcom = dev_get_drvdata(dev);
104462306a36Sopenharmony_ci
104562306a36Sopenharmony_ci	return dwc3_qcom_resume(qcom, true);
104662306a36Sopenharmony_ci}
104762306a36Sopenharmony_ci
104862306a36Sopenharmony_cistatic const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
104962306a36Sopenharmony_ci	SET_SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume)
105062306a36Sopenharmony_ci	SET_RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume,
105162306a36Sopenharmony_ci			   NULL)
105262306a36Sopenharmony_ci};
105362306a36Sopenharmony_ci
105462306a36Sopenharmony_cistatic const struct of_device_id dwc3_qcom_of_match[] = {
105562306a36Sopenharmony_ci	{ .compatible = "qcom,dwc3" },
105662306a36Sopenharmony_ci	{ }
105762306a36Sopenharmony_ci};
105862306a36Sopenharmony_ciMODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
105962306a36Sopenharmony_ci
106062306a36Sopenharmony_ci#ifdef CONFIG_ACPI
106162306a36Sopenharmony_cistatic const struct dwc3_acpi_pdata sdm845_acpi_pdata = {
106262306a36Sopenharmony_ci	.qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
106362306a36Sopenharmony_ci	.qscratch_base_size = SDM845_QSCRATCH_SIZE,
106462306a36Sopenharmony_ci	.dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
106562306a36Sopenharmony_ci	.hs_phy_irq_index = 1,
106662306a36Sopenharmony_ci	.dp_hs_phy_irq_index = 4,
106762306a36Sopenharmony_ci	.dm_hs_phy_irq_index = 3,
106862306a36Sopenharmony_ci	.ss_phy_irq_index = 2
106962306a36Sopenharmony_ci};
107062306a36Sopenharmony_ci
107162306a36Sopenharmony_cistatic const struct dwc3_acpi_pdata sdm845_acpi_urs_pdata = {
107262306a36Sopenharmony_ci	.qscratch_base_offset = SDM845_QSCRATCH_BASE_OFFSET,
107362306a36Sopenharmony_ci	.qscratch_base_size = SDM845_QSCRATCH_SIZE,
107462306a36Sopenharmony_ci	.dwc3_core_base_size = SDM845_DWC3_CORE_SIZE,
107562306a36Sopenharmony_ci	.hs_phy_irq_index = 1,
107662306a36Sopenharmony_ci	.dp_hs_phy_irq_index = 4,
107762306a36Sopenharmony_ci	.dm_hs_phy_irq_index = 3,
107862306a36Sopenharmony_ci	.ss_phy_irq_index = 2,
107962306a36Sopenharmony_ci	.is_urs = true,
108062306a36Sopenharmony_ci};
108162306a36Sopenharmony_ci
108262306a36Sopenharmony_cistatic const struct acpi_device_id dwc3_qcom_acpi_match[] = {
108362306a36Sopenharmony_ci	{ "QCOM2430", (unsigned long)&sdm845_acpi_pdata },
108462306a36Sopenharmony_ci	{ "QCOM0304", (unsigned long)&sdm845_acpi_urs_pdata },
108562306a36Sopenharmony_ci	{ "QCOM0497", (unsigned long)&sdm845_acpi_urs_pdata },
108662306a36Sopenharmony_ci	{ "QCOM04A6", (unsigned long)&sdm845_acpi_pdata },
108762306a36Sopenharmony_ci	{ },
108862306a36Sopenharmony_ci};
108962306a36Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, dwc3_qcom_acpi_match);
109062306a36Sopenharmony_ci#endif
109162306a36Sopenharmony_ci
109262306a36Sopenharmony_cistatic struct platform_driver dwc3_qcom_driver = {
109362306a36Sopenharmony_ci	.probe		= dwc3_qcom_probe,
109462306a36Sopenharmony_ci	.remove_new	= dwc3_qcom_remove,
109562306a36Sopenharmony_ci	.driver		= {
109662306a36Sopenharmony_ci		.name	= "dwc3-qcom",
109762306a36Sopenharmony_ci		.pm	= &dwc3_qcom_dev_pm_ops,
109862306a36Sopenharmony_ci		.of_match_table	= dwc3_qcom_of_match,
109962306a36Sopenharmony_ci		.acpi_match_table = ACPI_PTR(dwc3_qcom_acpi_match),
110062306a36Sopenharmony_ci	},
110162306a36Sopenharmony_ci};
110262306a36Sopenharmony_ci
110362306a36Sopenharmony_cimodule_platform_driver(dwc3_qcom_driver);
110462306a36Sopenharmony_ci
110562306a36Sopenharmony_ciMODULE_LICENSE("GPL v2");
110662306a36Sopenharmony_ciMODULE_DESCRIPTION("DesignWare DWC3 QCOM Glue Driver");
1107