File Index
Files and directories
Sign in
FILE

dwc3-qcom.c

File preview with syntax highlighting.

linux-6.19.14/drivers/usb/dwc3/dwc3-qcom.c C
  1// SPDX-License-Identifier: GPL-2.0
  2/* Copyright (c) 2018, The Linux Foundation. All rights reserved.
  3 *
  4 * Inspired by dwc3-of-simple.c
  5 */
  6
  7#include <linux/io.h>
  8#include <linux/of.h>
  9#include <linux/clk.h>
 10#include <linux/irq.h>
 11#include <linux/of_clk.h>
 12#include <linux/module.h>
 13#include <linux/kernel.h>
 14#include <linux/interconnect.h>
 15#include <linux/platform_device.h>
 16#include <linux/phy/phy.h>
 17#include <linux/usb/of.h>
 18#include <linux/reset.h>
 19#include <linux/iopoll.h>
 20#include <linux/usb/hcd.h>
 21#include <linux/usb.h>
 22#include "core.h"
 23#include "glue.h"
 24
 25/* USB QSCRATCH Hardware registers */
 26#define QSCRATCH_HS_PHY_CTRL			0x10
 27#define UTMI_OTG_VBUS_VALID			BIT(20)
 28#define SW_SESSVLD_SEL				BIT(28)
 29
 30#define QSCRATCH_SS_PHY_CTRL			0x30
 31#define LANE0_PWR_PRESENT			BIT(24)
 32
 33#define QSCRATCH_GENERAL_CFG			0x08
 34#define PIPE_UTMI_CLK_SEL			BIT(0)
 35#define PIPE3_PHYSTATUS_SW			BIT(3)
 36#define PIPE_UTMI_CLK_DIS			BIT(8)
 37
 38#define PWR_EVNT_LPM_IN_L2_MASK			BIT(4)
 39#define PWR_EVNT_LPM_OUT_L2_MASK		BIT(5)
 40
 41#define SDM845_QSCRATCH_BASE_OFFSET		0xf8800
 42#define SDM845_QSCRATCH_SIZE			0x400
 43#define SDM845_DWC3_CORE_SIZE			0xcd00
 44
 45/* Interconnect path bandwidths in MBps */
 46#define USB_MEMORY_AVG_HS_BW MBps_to_icc(240)
 47#define USB_MEMORY_PEAK_HS_BW MBps_to_icc(700)
 48#define USB_MEMORY_AVG_SS_BW  MBps_to_icc(1000)
 49#define USB_MEMORY_PEAK_SS_BW MBps_to_icc(2500)
 50#define APPS_USB_AVG_BW 0
 51#define APPS_USB_PEAK_BW MBps_to_icc(40)
 52
 53/* Qualcomm SoCs with multiport support has up to 4 ports */
 54#define DWC3_QCOM_MAX_PORTS	4
 55
 56static const u32 pwr_evnt_irq_stat_reg[DWC3_QCOM_MAX_PORTS] = {
 57	0x58,
 58	0x1dc,
 59	0x228,
 60	0x238,
 61};
 62
 63struct dwc3_qcom_port {
 64	int			qusb2_phy_irq;
 65	int			dp_hs_phy_irq;
 66	int			dm_hs_phy_irq;
 67	int			ss_phy_irq;
 68	enum usb_device_speed	usb2_speed;
 69};
 70
 71struct dwc3_qcom {
 72	struct device		*dev;
 73	void __iomem		*qscratch_base;
 74	struct dwc3		dwc;
 75	struct clk_bulk_data	*clks;
 76	int			num_clocks;
 77	struct reset_control	*resets;
 78	struct dwc3_qcom_port	ports[DWC3_QCOM_MAX_PORTS];
 79	u8			num_ports;
 80
 81	enum usb_dr_mode	mode;
 82	bool			is_suspended;
 83	bool			pm_suspended;
 84	struct icc_path		*icc_path_ddr;
 85	struct icc_path		*icc_path_apps;
 86
 87	enum usb_role		current_role;
 88};
 89
 90#define to_dwc3_qcom(d) container_of((d), struct dwc3_qcom, dwc)
 91
 92static inline void dwc3_qcom_setbits(void __iomem *base, u32 offset, u32 val)
 93{
 94	u32 reg;
 95
 96	reg = readl(base + offset);
 97	reg |= val;
 98	writel(reg, base + offset);
 99
100	/* ensure that above write is through */
101	readl(base + offset);
102}
103
104static inline void dwc3_qcom_clrbits(void __iomem *base, u32 offset, u32 val)
105{
106	u32 reg;
107
108	reg = readl(base + offset);
109	reg &= ~val;
110	writel(reg, base + offset);
111
112	/* ensure that above write is through */
113	readl(base + offset);
114}
115
116static void dwc3_qcom_vbus_override_enable(struct dwc3_qcom *qcom, bool enable)
117{
118	if (enable) {
119		dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL,
120				  LANE0_PWR_PRESENT);
121		dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL,
122				  UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
123	} else {
124		dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_SS_PHY_CTRL,
125				  LANE0_PWR_PRESENT);
126		dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_HS_PHY_CTRL,
127				  UTMI_OTG_VBUS_VALID | SW_SESSVLD_SEL);
128	}
129}
130
131static int dwc3_qcom_interconnect_enable(struct dwc3_qcom *qcom)
132{
133	int ret;
134
135	ret = icc_enable(qcom->icc_path_ddr);
136	if (ret)
137		return ret;
138
139	ret = icc_enable(qcom->icc_path_apps);
140	if (ret)
141		icc_disable(qcom->icc_path_ddr);
142
143	return ret;
144}
145
146static int dwc3_qcom_interconnect_disable(struct dwc3_qcom *qcom)
147{
148	int ret;
149
150	ret = icc_disable(qcom->icc_path_ddr);
151	if (ret)
152		return ret;
153
154	ret = icc_disable(qcom->icc_path_apps);
155	if (ret)
156		icc_enable(qcom->icc_path_ddr);
157
158	return ret;
159}
160
161/**
162 * dwc3_qcom_interconnect_init() - Get interconnect path handles
163 * and set bandwidth.
164 * @qcom:			Pointer to the concerned usb core.
165 *
166 */
167static int dwc3_qcom_interconnect_init(struct dwc3_qcom *qcom)
168{
169	enum usb_device_speed max_speed;
170	struct device *dev = qcom->dev;
171	int ret;
172
173	qcom->icc_path_ddr = of_icc_get(dev, "usb-ddr");
174	if (IS_ERR(qcom->icc_path_ddr)) {
175		return dev_err_probe(dev, PTR_ERR(qcom->icc_path_ddr),
176				     "failed to get usb-ddr path\n");
177	}
178
179	qcom->icc_path_apps = of_icc_get(dev, "apps-usb");
180	if (IS_ERR(qcom->icc_path_apps)) {
181		ret = dev_err_probe(dev, PTR_ERR(qcom->icc_path_apps),
182				    "failed to get apps-usb path\n");
183		goto put_path_ddr;
184	}
185
186	max_speed = usb_get_maximum_speed(qcom->dwc.dev);
187	if (max_speed >= USB_SPEED_SUPER || max_speed == USB_SPEED_UNKNOWN) {
188		ret = icc_set_bw(qcom->icc_path_ddr,
189				USB_MEMORY_AVG_SS_BW, USB_MEMORY_PEAK_SS_BW);
190	} else {
191		ret = icc_set_bw(qcom->icc_path_ddr,
192				USB_MEMORY_AVG_HS_BW, USB_MEMORY_PEAK_HS_BW);
193	}
194	if (ret) {
195		dev_err(dev, "failed to set bandwidth for usb-ddr path: %d\n", ret);
196		goto put_path_apps;
197	}
198
199	ret = icc_set_bw(qcom->icc_path_apps, APPS_USB_AVG_BW, APPS_USB_PEAK_BW);
200	if (ret) {
201		dev_err(dev, "failed to set bandwidth for apps-usb path: %d\n", ret);
202		goto put_path_apps;
203	}
204
205	return 0;
206
207put_path_apps:
208	icc_put(qcom->icc_path_apps);
209put_path_ddr:
210	icc_put(qcom->icc_path_ddr);
211	return ret;
212}
213
214/**
215 * dwc3_qcom_interconnect_exit() - Release interconnect path handles
216 * @qcom:			Pointer to the concerned usb core.
217 *
218 * This function is used to release interconnect path handle.
219 */
220static void dwc3_qcom_interconnect_exit(struct dwc3_qcom *qcom)
221{
222	icc_put(qcom->icc_path_ddr);
223	icc_put(qcom->icc_path_apps);
224}
225
226/* Only usable in contexts where the role can not change. */
227static bool dwc3_qcom_is_host(struct dwc3_qcom *qcom)
228{
229	return qcom->dwc.xhci;
230}
231
232static enum usb_device_speed dwc3_qcom_read_usb2_speed(struct dwc3_qcom *qcom, int port_index)
233{
234	struct usb_device *udev;
235	struct usb_hcd __maybe_unused *hcd;
236	struct dwc3 *dwc = &qcom->dwc;
237
238	/*
239	 * FIXME: Fix this layering violation.
240	 */
241	hcd = platform_get_drvdata(dwc->xhci);
242
243#ifdef CONFIG_USB
244	udev = usb_hub_find_child(hcd->self.root_hub, port_index + 1);
245#else
246	udev = NULL;
247#endif
248	if (!udev)
249		return USB_SPEED_UNKNOWN;
250
251	return udev->speed;
252}
253
254static void dwc3_qcom_enable_wakeup_irq(int irq, unsigned int polarity)
255{
256	if (!irq)
257		return;
258
259	if (polarity)
260		irq_set_irq_type(irq, polarity);
261
262	enable_irq(irq);
263	enable_irq_wake(irq);
264}
265
266static void dwc3_qcom_disable_wakeup_irq(int irq)
267{
268	if (!irq)
269		return;
270
271	disable_irq_wake(irq);
272	disable_irq_nosync(irq);
273}
274
275static void dwc3_qcom_disable_port_interrupts(struct dwc3_qcom_port *port)
276{
277	dwc3_qcom_disable_wakeup_irq(port->qusb2_phy_irq);
278
279	if (port->usb2_speed == USB_SPEED_LOW) {
280		dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq);
281	} else if ((port->usb2_speed == USB_SPEED_HIGH) ||
282			(port->usb2_speed == USB_SPEED_FULL)) {
283		dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq);
284	} else {
285		dwc3_qcom_disable_wakeup_irq(port->dp_hs_phy_irq);
286		dwc3_qcom_disable_wakeup_irq(port->dm_hs_phy_irq);
287	}
288
289	dwc3_qcom_disable_wakeup_irq(port->ss_phy_irq);
290}
291
292static void dwc3_qcom_enable_port_interrupts(struct dwc3_qcom_port *port)
293{
294	dwc3_qcom_enable_wakeup_irq(port->qusb2_phy_irq, 0);
295
296	/*
297	 * Configure DP/DM line interrupts based on the USB2 device attached to
298	 * the root hub port. When HS/FS device is connected, configure the DP line
299	 * as falling edge to detect both disconnect and remote wakeup scenarios. When
300	 * LS device is connected, configure DM line as falling edge to detect both
301	 * disconnect and remote wakeup. When no device is connected, configure both
302	 * DP and DM lines as rising edge to detect HS/HS/LS device connect scenario.
303	 */
304
305	if (port->usb2_speed == USB_SPEED_LOW) {
306		dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq,
307					    IRQ_TYPE_EDGE_FALLING);
308	} else if ((port->usb2_speed == USB_SPEED_HIGH) ||
309			(port->usb2_speed == USB_SPEED_FULL)) {
310		dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq,
311					    IRQ_TYPE_EDGE_FALLING);
312	} else {
313		dwc3_qcom_enable_wakeup_irq(port->dp_hs_phy_irq,
314					    IRQ_TYPE_EDGE_RISING);
315		dwc3_qcom_enable_wakeup_irq(port->dm_hs_phy_irq,
316					    IRQ_TYPE_EDGE_RISING);
317	}
318
319	dwc3_qcom_enable_wakeup_irq(port->ss_phy_irq, 0);
320}
321
322static void dwc3_qcom_disable_interrupts(struct dwc3_qcom *qcom)
323{
324	int i;
325
326	for (i = 0; i < qcom->num_ports; i++)
327		dwc3_qcom_disable_port_interrupts(&qcom->ports[i]);
328}
329
330static void dwc3_qcom_enable_interrupts(struct dwc3_qcom *qcom)
331{
332	int i;
333
334	for (i = 0; i < qcom->num_ports; i++)
335		dwc3_qcom_enable_port_interrupts(&qcom->ports[i]);
336}
337
338static int dwc3_qcom_suspend(struct dwc3_qcom *qcom, bool wakeup)
339{
340	u32 val;
341	int i, ret;
342
343	if (qcom->is_suspended)
344		return 0;
345
346	for (i = 0; i < qcom->num_ports; i++) {
347		val = readl(qcom->qscratch_base + pwr_evnt_irq_stat_reg[i]);
348		if (!(val & PWR_EVNT_LPM_IN_L2_MASK))
349			dev_err(qcom->dev, "port-%d HS-PHY not in L2\n", i + 1);
350	}
351	clk_bulk_disable_unprepare(qcom->num_clocks, qcom->clks);
352
353	ret = dwc3_qcom_interconnect_disable(qcom);
354	if (ret)
355		dev_warn(qcom->dev, "failed to disable interconnect: %d\n", ret);
356
357	/*
358	 * The role is stable during suspend as role switching is done from a
359	 * freezable workqueue.
360	 */
361	if (dwc3_qcom_is_host(qcom) && wakeup) {
362		for (i = 0; i < qcom->num_ports; i++)
363			qcom->ports[i].usb2_speed = dwc3_qcom_read_usb2_speed(qcom, i);
364		dwc3_qcom_enable_interrupts(qcom);
365	}
366
367	qcom->is_suspended = true;
368
369	return 0;
370}
371
372static int dwc3_qcom_resume(struct dwc3_qcom *qcom, bool wakeup)
373{
374	int ret;
375	int i;
376
377	if (!qcom->is_suspended)
378		return 0;
379
380	if (dwc3_qcom_is_host(qcom) && wakeup)
381		dwc3_qcom_disable_interrupts(qcom);
382
383	ret = clk_bulk_prepare_enable(qcom->num_clocks, qcom->clks);
384	if (ret < 0)
385		return ret;
386
387	ret = dwc3_qcom_interconnect_enable(qcom);
388	if (ret)
389		dev_warn(qcom->dev, "failed to enable interconnect: %d\n", ret);
390
391	/* Clear existing events from PHY related to L2 in/out */
392	for (i = 0; i < qcom->num_ports; i++) {
393		dwc3_qcom_setbits(qcom->qscratch_base,
394				  pwr_evnt_irq_stat_reg[i],
395				  PWR_EVNT_LPM_IN_L2_MASK | PWR_EVNT_LPM_OUT_L2_MASK);
396	}
397
398	qcom->is_suspended = false;
399
400	return 0;
401}
402
403static irqreturn_t qcom_dwc3_resume_irq(int irq, void *data)
404{
405	struct dwc3_qcom *qcom = data;
406	struct dwc3 *dwc = &qcom->dwc;
407
408	/* If pm_suspended then let pm_resume take care of resuming h/w */
409	if (qcom->pm_suspended)
410		return IRQ_HANDLED;
411
412	/*
413	 * This is safe as role switching is done from a freezable workqueue
414	 * and the wakeup interrupts are disabled as part of resume.
415	 */
416	if (dwc3_qcom_is_host(qcom))
417		pm_runtime_resume(&dwc->xhci->dev);
418
419	return IRQ_HANDLED;
420}
421
422static void dwc3_qcom_select_utmi_clk(struct dwc3_qcom *qcom)
423{
424	/* Configure dwc3 to use UTMI clock as PIPE clock not present */
425	dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
426			  PIPE_UTMI_CLK_DIS);
427
428	usleep_range(100, 1000);
429
430	dwc3_qcom_setbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
431			  PIPE_UTMI_CLK_SEL | PIPE3_PHYSTATUS_SW);
432
433	usleep_range(100, 1000);
434
435	dwc3_qcom_clrbits(qcom->qscratch_base, QSCRATCH_GENERAL_CFG,
436			  PIPE_UTMI_CLK_DIS);
437}
438
439static int dwc3_qcom_request_irq(struct dwc3_qcom *qcom, int irq,
440				 const char *name)
441{
442	int ret;
443
444	/* Keep wakeup interrupts disabled until suspend */
445	ret = devm_request_threaded_irq(qcom->dev, irq, NULL,
446					qcom_dwc3_resume_irq,
447					IRQF_ONESHOT | IRQF_NO_AUTOEN,
448					name, qcom);
449	if (ret)
450		dev_err(qcom->dev, "failed to request irq %s: %d\n", name, ret);
451
452	return ret;
453}
454
455static int dwc3_qcom_setup_port_irq(struct dwc3_qcom *qcom,
456				    struct platform_device *pdev,
457				    int port_index, bool is_multiport)
458{
459	const char *irq_name;
460	int irq;
461	int ret;
462
463	if (is_multiport)
464		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_%d", port_index + 1);
465	else
466		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dp_hs_phy_irq");
467	if (!irq_name)
468		return -ENOMEM;
469
470	irq = platform_get_irq_byname_optional(pdev, irq_name);
471	if (irq > 0) {
472		ret = dwc3_qcom_request_irq(qcom, irq, irq_name);
473		if (ret)
474			return ret;
475		qcom->ports[port_index].dp_hs_phy_irq = irq;
476	}
477
478	if (is_multiport)
479		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dm_hs_phy_%d", port_index + 1);
480	else
481		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "dm_hs_phy_irq");
482	if (!irq_name)
483		return -ENOMEM;
484
485	irq = platform_get_irq_byname_optional(pdev, irq_name);
486	if (irq > 0) {
487		ret = dwc3_qcom_request_irq(qcom, irq, irq_name);
488		if (ret)
489			return ret;
490		qcom->ports[port_index].dm_hs_phy_irq = irq;
491	}
492
493	if (is_multiport)
494		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ss_phy_%d", port_index + 1);
495	else
496		irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "ss_phy_irq");
497	if (!irq_name)
498		return -ENOMEM;
499
500	irq = platform_get_irq_byname_optional(pdev, irq_name);
501	if (irq > 0) {
502		ret = dwc3_qcom_request_irq(qcom, irq, irq_name);
503		if (ret)
504			return ret;
505		qcom->ports[port_index].ss_phy_irq = irq;
506	}
507
508	if (is_multiport)
509		return 0;
510
511	irq = platform_get_irq_byname_optional(pdev, "qusb2_phy");
512	if (irq > 0) {
513		ret = dwc3_qcom_request_irq(qcom, irq, "qusb2_phy");
514		if (ret)
515			return ret;
516		qcom->ports[port_index].qusb2_phy_irq = irq;
517	}
518
519	return 0;
520}
521
522static int dwc3_qcom_find_num_ports(struct platform_device *pdev)
523{
524	char irq_name[14];
525	int port_num;
526	int irq;
527
528	irq = platform_get_irq_byname_optional(pdev, "dp_hs_phy_1");
529	if (irq <= 0)
530		return 1;
531
532	for (port_num = 2; port_num <= DWC3_QCOM_MAX_PORTS; port_num++) {
533		sprintf(irq_name, "dp_hs_phy_%d", port_num);
534
535		irq = platform_get_irq_byname_optional(pdev, irq_name);
536		if (irq <= 0)
537			return port_num - 1;
538	}
539
540	return DWC3_QCOM_MAX_PORTS;
541}
542
543static int dwc3_qcom_setup_irq(struct dwc3_qcom *qcom, struct platform_device *pdev)
544{
545	bool is_multiport;
546	int ret;
547	int i;
548
549	qcom->num_ports = dwc3_qcom_find_num_ports(pdev);
550	is_multiport = (qcom->num_ports > 1);
551
552	for (i = 0; i < qcom->num_ports; i++) {
553		ret = dwc3_qcom_setup_port_irq(qcom, pdev, i, is_multiport);
554		if (ret)
555			return ret;
556	}
557
558	return 0;
559}
560
561static void dwc3_qcom_set_role_notifier(struct dwc3 *dwc, enum usb_role next_role)
562{
563	struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
564
565	if (qcom->current_role == next_role)
566		return;
567
568	if (pm_runtime_resume_and_get(qcom->dev)) {
569		dev_dbg(qcom->dev, "Failed to resume device\n");
570		return;
571	}
572
573	if (qcom->current_role == USB_ROLE_DEVICE)
574		dwc3_qcom_vbus_override_enable(qcom, false);
575	else if (qcom->current_role != USB_ROLE_DEVICE)
576		dwc3_qcom_vbus_override_enable(qcom, true);
577
578	pm_runtime_mark_last_busy(qcom->dev);
579	pm_runtime_put_sync(qcom->dev);
580
581	/*
582	 * Current role changes via usb_role_switch_set_role callback protected
583	 * internally by mutex lock.
584	 */
585	qcom->current_role = next_role;
586}
587
588static void dwc3_qcom_run_stop_notifier(struct dwc3 *dwc, bool is_on)
589{
590	struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
591
592	/*
593	 * When autosuspend is enabled and controller goes to suspend
594	 * after removing UDC from userspace, the next UDC write needs
595	 * setting of QSCRATCH VBUS_VALID to "1" to generate a connect
596	 * done event.
597	 */
598	if (!is_on)
599		return;
600
601	dwc3_qcom_vbus_override_enable(qcom, true);
602	pm_runtime_mark_last_busy(qcom->dev);
603}
604
605struct dwc3_glue_ops dwc3_qcom_glue_ops = {
606	.pre_set_role	= dwc3_qcom_set_role_notifier,
607	.pre_run_stop	= dwc3_qcom_run_stop_notifier,
608};
609
610static int dwc3_qcom_probe(struct platform_device *pdev)
611{
612	struct dwc3_probe_data	probe_data = {};
613	struct device		*dev = &pdev->dev;
614	struct dwc3_qcom	*qcom;
615	struct resource		res;
616	struct resource		*r;
617	int			ret;
618	bool			ignore_pipe_clk;
619	bool			wakeup_source;
620
621	qcom = devm_kzalloc(&pdev->dev, sizeof(*qcom), GFP_KERNEL);
622	if (!qcom)
623		return -ENOMEM;
624
625	qcom->dev = &pdev->dev;
626
627	qcom->resets = devm_reset_control_array_get_optional_exclusive(dev);
628	if (IS_ERR(qcom->resets)) {
629		return dev_err_probe(&pdev->dev, PTR_ERR(qcom->resets),
630				     "failed to get resets\n");
631	}
632
633	ret = devm_clk_bulk_get_all(&pdev->dev, &qcom->clks);
634	if (ret < 0)
635		return dev_err_probe(dev, ret, "failed to get clocks\n");
636	qcom->num_clocks = ret;
637
638	ret = reset_control_assert(qcom->resets);
639	if (ret) {
640		dev_err(&pdev->dev, "failed to assert resets, err=%d\n", ret);
641		return ret;
642	}
643
644	usleep_range(10, 1000);
645
646	ret = reset_control_deassert(qcom->resets);
647	if (ret) {
648		dev_err(&pdev->dev, "failed to deassert resets, err=%d\n", ret);
649		return ret;
650	}
651
652	ret = clk_bulk_prepare_enable(qcom->num_clocks, qcom->clks);
653	if (ret < 0)
654		return ret;
655
656	r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
657	if (!r) {
658		ret = -EINVAL;
659		goto clk_disable;
660	}
661	res = *r;
662	res.end = res.start + SDM845_QSCRATCH_BASE_OFFSET;
663
664	qcom->qscratch_base = devm_ioremap(dev, res.end, SDM845_QSCRATCH_SIZE);
665	if (!qcom->qscratch_base) {
666		dev_err(dev, "failed to map qscratch region\n");
667		ret = -ENOMEM;
668		goto clk_disable;
669	}
670
671	ret = dwc3_qcom_setup_irq(qcom, pdev);
672	if (ret) {
673		dev_err(dev, "failed to setup IRQs, err=%d\n", ret);
674		goto clk_disable;
675	}
676
677	/*
678	 * Disable pipe_clk requirement if specified. Used when dwc3
679	 * operates without SSPHY and only HS/FS/LS modes are supported.
680	 */
681	ignore_pipe_clk = device_property_read_bool(dev,
682				"qcom,select-utmi-as-pipe-clk");
683	if (ignore_pipe_clk)
684		dwc3_qcom_select_utmi_clk(qcom);
685
686	qcom->mode = usb_get_dr_mode(dev);
687
688	if (qcom->mode == USB_DR_MODE_HOST) {
689		qcom->current_role = USB_ROLE_HOST;
690	} else if (qcom->mode == USB_DR_MODE_PERIPHERAL) {
691		qcom->current_role = USB_ROLE_DEVICE;
692		dwc3_qcom_vbus_override_enable(qcom, true);
693	} else {
694		if ((device_property_read_bool(dev, "usb-role-switch")) &&
695		    (usb_get_role_switch_default_mode(dev) == USB_DR_MODE_HOST))
696			qcom->current_role = USB_ROLE_HOST;
697		else
698			qcom->current_role = USB_ROLE_DEVICE;
699	}
700
701	qcom->dwc.glue_ops = &dwc3_qcom_glue_ops;
702
703	qcom->dwc.dev = dev;
704	probe_data.dwc = &qcom->dwc;
705	probe_data.res = &res;
706	probe_data.ignore_clocks_and_resets = true;
707	probe_data.properties = DWC3_DEFAULT_PROPERTIES;
708	ret = dwc3_core_probe(&probe_data);
709	if (ret)  {
710		ret = dev_err_probe(dev, ret, "failed to register DWC3 Core\n");
711		goto clk_disable;
712	}
713
714	ret = dwc3_qcom_interconnect_init(qcom);
715	if (ret)
716		goto remove_core;
717
718	wakeup_source = of_property_read_bool(dev->of_node, "wakeup-source");
719	device_init_wakeup(&pdev->dev, wakeup_source);
720
721	qcom->is_suspended = false;
722
723	return 0;
724
725remove_core:
726	dwc3_core_remove(&qcom->dwc);
727clk_disable:
728	clk_bulk_disable_unprepare(qcom->num_clocks, qcom->clks);
729
730	return ret;
731}
732
733static void dwc3_qcom_remove(struct platform_device *pdev)
734{
735	struct dwc3 *dwc = platform_get_drvdata(pdev);
736	struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
737
738	if (pm_runtime_resume_and_get(qcom->dev) < 0)
739		return;
740
741	dwc3_core_remove(&qcom->dwc);
742	clk_bulk_disable_unprepare(qcom->num_clocks, qcom->clks);
743	dwc3_qcom_interconnect_exit(qcom);
744
745	pm_runtime_put_noidle(qcom->dev);
746}
747
748static int dwc3_qcom_pm_suspend(struct device *dev)
749{
750	struct dwc3 *dwc = dev_get_drvdata(dev);
751	struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
752	bool wakeup = device_may_wakeup(dev);
753	int ret;
754
755	ret = dwc3_pm_suspend(&qcom->dwc);
756	if (ret)
757		return ret;
758
759	ret = dwc3_qcom_suspend(qcom, wakeup);
760	if (ret)
761		return ret;
762
763	qcom->pm_suspended = true;
764
765	return 0;
766}
767
768static int dwc3_qcom_pm_resume(struct device *dev)
769{
770	struct dwc3 *dwc = dev_get_drvdata(dev);
771	struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
772	bool wakeup = device_may_wakeup(dev);
773	int ret;
774
775	ret = dwc3_qcom_resume(qcom, wakeup);
776	if (ret)
777		return ret;
778
779	qcom->pm_suspended = false;
780
781	ret = dwc3_pm_resume(&qcom->dwc);
782	if (ret)
783		return ret;
784
785	return 0;
786}
787
788static void dwc3_qcom_complete(struct device *dev)
789{
790	struct dwc3 *dwc = dev_get_drvdata(dev);
791
792	dwc3_pm_complete(dwc);
793}
794
795static int dwc3_qcom_prepare(struct device *dev)
796{
797	struct dwc3 *dwc = dev_get_drvdata(dev);
798
799	return dwc3_pm_prepare(dwc);
800}
801
802static int dwc3_qcom_runtime_suspend(struct device *dev)
803{
804	struct dwc3 *dwc = dev_get_drvdata(dev);
805	struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
806	int ret;
807
808	ret = dwc3_runtime_suspend(&qcom->dwc);
809	if (ret)
810		return ret;
811
812	return dwc3_qcom_suspend(qcom, true);
813}
814
815static int dwc3_qcom_runtime_resume(struct device *dev)
816{
817	struct dwc3 *dwc = dev_get_drvdata(dev);
818	struct dwc3_qcom *qcom = to_dwc3_qcom(dwc);
819	int ret;
820
821	ret = dwc3_qcom_resume(qcom, true);
822	if (ret)
823		return ret;
824
825	return dwc3_runtime_resume(&qcom->dwc);
826}
827
828static int dwc3_qcom_runtime_idle(struct device *dev)
829{
830	return dwc3_runtime_idle(dev_get_drvdata(dev));
831}
832
833static const struct dev_pm_ops dwc3_qcom_dev_pm_ops = {
834	SYSTEM_SLEEP_PM_OPS(dwc3_qcom_pm_suspend, dwc3_qcom_pm_resume)
835	RUNTIME_PM_OPS(dwc3_qcom_runtime_suspend, dwc3_qcom_runtime_resume,
836			   dwc3_qcom_runtime_idle)
837	.complete = pm_sleep_ptr(dwc3_qcom_complete),
838	.prepare = pm_sleep_ptr(dwc3_qcom_prepare),
839};
840
841static const struct of_device_id dwc3_qcom_of_match[] = {
842	{ .compatible = "qcom,snps-dwc3" },
843	{ }
844};
845MODULE_DEVICE_TABLE(of, dwc3_qcom_of_match);
846
847static struct platform_driver dwc3_qcom_driver = {
848	.probe		= dwc3_qcom_probe,
849	.remove		= dwc3_qcom_remove,
850	.shutdown	= dwc3_qcom_remove,
851	.driver		= {
852		.name	= "dwc3-qcom",
853		.pm	= pm_ptr(&dwc3_qcom_dev_pm_ops),
854		.of_match_table	= dwc3_qcom_of_match,
855	},
856};
857
858module_platform_driver(dwc3_qcom_driver);
859
860MODULE_LICENSE("GPL v2");
861MODULE_DESCRIPTION("DesignWare DWC3 QCOM Glue Driver");
~/ Read-only file preview.