File Index
Files and directories
Sign in
FILE

ci_hdrc_imx.c

File preview with syntax highlighting.

linux-6.19.14/drivers/usb/chipidea/ci_hdrc_imx.c C
  1// SPDX-License-Identifier: GPL-2.0+
  2/*
  3 * Copyright 2012 Freescale Semiconductor, Inc.
  4 * Copyright 2025 NXP
  5 * Copyright (C) 2012 Marek Vasut <marex@denx.de>
  6 * on behalf of DENX Software Engineering GmbH
  7 */
  8
  9#include <linux/module.h>
 10#include <linux/irq.h>
 11#include <linux/of.h>
 12#include <linux/of_platform.h>
 13#include <linux/platform_device.h>
 14#include <linux/pm_runtime.h>
 15#include <linux/usb/chipidea.h>
 16#include <linux/usb/of.h>
 17#include <linux/clk.h>
 18#include <linux/pinctrl/consumer.h>
 19#include <linux/pm_qos.h>
 20
 21#include "ci.h"
 22#include "ci_hdrc_imx.h"
 23
 24struct ci_hdrc_imx_platform_flag {
 25	unsigned int flags;
 26};
 27
 28static const struct ci_hdrc_imx_platform_flag imx23_usb_data = {
 29	.flags = CI_HDRC_TURN_VBUS_EARLY_ON |
 30		CI_HDRC_DISABLE_STREAMING,
 31};
 32
 33static const struct ci_hdrc_imx_platform_flag imx27_usb_data = {
 34	.flags = CI_HDRC_DISABLE_STREAMING,
 35};
 36
 37static const struct ci_hdrc_imx_platform_flag imx28_usb_data = {
 38	.flags = CI_HDRC_IMX28_WRITE_FIX |
 39		CI_HDRC_TURN_VBUS_EARLY_ON |
 40		CI_HDRC_DISABLE_STREAMING,
 41};
 42
 43static const struct ci_hdrc_imx_platform_flag imx6q_usb_data = {
 44	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
 45		CI_HDRC_TURN_VBUS_EARLY_ON |
 46		CI_HDRC_DISABLE_STREAMING,
 47};
 48
 49static const struct ci_hdrc_imx_platform_flag imx6sl_usb_data = {
 50	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
 51		CI_HDRC_TURN_VBUS_EARLY_ON |
 52		CI_HDRC_DISABLE_HOST_STREAMING,
 53};
 54
 55static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = {
 56	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
 57		CI_HDRC_TURN_VBUS_EARLY_ON |
 58		CI_HDRC_DISABLE_HOST_STREAMING,
 59};
 60
 61static const struct ci_hdrc_imx_platform_flag imx6ul_usb_data = {
 62	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
 63		CI_HDRC_TURN_VBUS_EARLY_ON |
 64		CI_HDRC_DISABLE_DEVICE_STREAMING,
 65};
 66
 67static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
 68	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM,
 69};
 70
 71static const struct ci_hdrc_imx_platform_flag imx7ulp_usb_data = {
 72	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
 73		CI_HDRC_HAS_PORTSC_PEC_MISSED |
 74		CI_HDRC_PMQOS,
 75};
 76
 77static const struct ci_hdrc_imx_platform_flag imx8ulp_usb_data = {
 78	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
 79		CI_HDRC_HAS_PORTSC_PEC_MISSED,
 80};
 81
 82static const struct ci_hdrc_imx_platform_flag imx95_usb_data = {
 83	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM | CI_HDRC_OUT_BAND_WAKEUP,
 84};
 85
 86static const struct ci_hdrc_imx_platform_flag s32g_usb_data = {
 87	.flags = CI_HDRC_DISABLE_HOST_STREAMING,
 88};
 89
 90static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
 91	{ .compatible = "fsl,imx23-usb", .data = &imx23_usb_data},
 92	{ .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
 93	{ .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
 94	{ .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
 95	{ .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data},
 96	{ .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
 97	{ .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data},
 98	{ .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data},
 99	{ .compatible = "fsl,imx7ulp-usb", .data = &imx7ulp_usb_data},
100	{ .compatible = "fsl,imx8ulp-usb", .data = &imx8ulp_usb_data},
101	{ .compatible = "fsl,imx95-usb", .data = &imx95_usb_data},
102	{ .compatible = "nxp,s32g2-usb", .data = &s32g_usb_data},
103	{ /* sentinel */ }
104};
105MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
106
107struct ci_hdrc_imx_data {
108	struct usb_phy *phy;
109	struct platform_device *ci_pdev;
110	struct clk *clk;
111	struct clk *clk_wakeup;
112	struct imx_usbmisc_data *usbmisc_data;
113	int wakeup_irq;
114	bool supports_runtime_pm;
115	bool override_phy_control;
116	bool in_lpm;
117	struct pinctrl *pinctrl;
118	struct pinctrl_state *pinctrl_hsic_active;
119	struct regulator *hsic_pad_regulator;
120	/* SoC before i.mx6 (except imx23/imx28) needs three clks */
121	bool need_three_clks;
122	struct clk *clk_ipg;
123	struct clk *clk_ahb;
124	struct clk *clk_per;
125	/* --------------------------------- */
126	struct pm_qos_request pm_qos_req;
127	const struct ci_hdrc_imx_platform_flag *plat_data;
128};
129
130/* Common functions shared by usbmisc drivers */
131
132static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
133{
134	struct platform_device *misc_pdev;
135	struct device_node *np = dev->of_node;
136	struct of_phandle_args args;
137	struct imx_usbmisc_data *data;
138	int ret;
139
140	/*
141	 * In case the fsl,usbmisc property is not present this device doesn't
142	 * need usbmisc. Return NULL (which is no error here)
143	 */
144	if (!of_property_present(np, "fsl,usbmisc"))
145		return NULL;
146
147	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
148	if (!data)
149		return ERR_PTR(-ENOMEM);
150
151	ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells",
152					0, &args);
153	if (ret) {
154		dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n",
155			ret);
156		return ERR_PTR(ret);
157	}
158
159	data->index = args.args[0];
160
161	misc_pdev = of_find_device_by_node(args.np);
162	of_node_put(args.np);
163
164	if (!misc_pdev)
165		return ERR_PTR(-EPROBE_DEFER);
166
167	if (!platform_get_drvdata(misc_pdev)) {
168		put_device(&misc_pdev->dev);
169		return ERR_PTR(-EPROBE_DEFER);
170	}
171	data->dev = &misc_pdev->dev;
172
173	/*
174	 * Check the various over current related properties. If over current
175	 * detection is disabled we're not interested in the polarity.
176	 */
177	if (of_property_read_bool(np, "disable-over-current")) {
178		data->disable_oc = 1;
179	} else if (of_property_read_bool(np, "over-current-active-high")) {
180		data->oc_pol_active_low = 0;
181		data->oc_pol_configured = 1;
182	} else if (of_property_read_bool(np, "over-current-active-low")) {
183		data->oc_pol_active_low = 1;
184		data->oc_pol_configured = 1;
185	} else {
186		dev_warn(dev, "No over current polarity defined\n");
187	}
188
189	data->pwr_pol = of_property_read_bool(np, "power-active-high");
190	data->evdo = of_property_read_bool(np, "external-vbus-divider");
191
192	if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI)
193		data->ulpi = 1;
194
195	if (of_property_read_u32(np, "samsung,picophy-pre-emp-curr-control",
196			&data->emp_curr_control))
197		data->emp_curr_control = -1;
198	if (of_property_read_u32(np, "samsung,picophy-dc-vol-level-adjust",
199			&data->dc_vol_level_adjust))
200		data->dc_vol_level_adjust = -1;
201	if (of_property_read_u32(np, "fsl,picophy-rise-fall-time-adjust",
202			&data->rise_fall_time_adjust))
203		data->rise_fall_time_adjust = -1;
204
205	return data;
206}
207
208/* End of common functions shared by usbmisc drivers*/
209static int imx_get_clks(struct device *dev)
210{
211	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
212	int ret = 0;
213
214	data->clk_ipg = devm_clk_get(dev, "ipg");
215	if (IS_ERR(data->clk_ipg)) {
216		/* If the platform only needs one primary clock */
217		data->clk = devm_clk_get(dev, NULL);
218		if (IS_ERR(data->clk)) {
219			ret = PTR_ERR(data->clk);
220			dev_err(dev,
221				"Failed to get clks, err=%ld,%ld\n",
222				PTR_ERR(data->clk), PTR_ERR(data->clk_ipg));
223			return ret;
224		}
225		/* Get wakeup clock. Not all of the platforms need to
226		 * handle this clock. So make it optional.
227		 */
228		data->clk_wakeup = devm_clk_get_optional(dev, "usb_wakeup");
229		if (IS_ERR(data->clk_wakeup))
230			ret = dev_err_probe(dev, PTR_ERR(data->clk_wakeup),
231					"Failed to get wakeup clk\n");
232		return ret;
233	}
234
235	data->clk_ahb = devm_clk_get(dev, "ahb");
236	if (IS_ERR(data->clk_ahb)) {
237		ret = PTR_ERR(data->clk_ahb);
238		dev_err(dev,
239			"Failed to get ahb clock, err=%d\n", ret);
240		return ret;
241	}
242
243	data->clk_per = devm_clk_get(dev, "per");
244	if (IS_ERR(data->clk_per)) {
245		ret = PTR_ERR(data->clk_per);
246		dev_err(dev,
247			"Failed to get per clock, err=%d\n", ret);
248		return ret;
249	}
250
251	data->need_three_clks = true;
252	return ret;
253}
254
255static int imx_prepare_enable_clks(struct device *dev)
256{
257	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
258	int ret = 0;
259
260	if (data->need_three_clks) {
261		ret = clk_prepare_enable(data->clk_ipg);
262		if (ret) {
263			dev_err(dev,
264				"Failed to prepare/enable ipg clk, err=%d\n",
265				ret);
266			return ret;
267		}
268
269		ret = clk_prepare_enable(data->clk_ahb);
270		if (ret) {
271			dev_err(dev,
272				"Failed to prepare/enable ahb clk, err=%d\n",
273				ret);
274			clk_disable_unprepare(data->clk_ipg);
275			return ret;
276		}
277
278		ret = clk_prepare_enable(data->clk_per);
279		if (ret) {
280			dev_err(dev,
281				"Failed to prepare/enable per clk, err=%d\n",
282				ret);
283			clk_disable_unprepare(data->clk_ahb);
284			clk_disable_unprepare(data->clk_ipg);
285			return ret;
286		}
287	} else {
288		ret = clk_prepare_enable(data->clk);
289		if (ret) {
290			dev_err(dev,
291				"Failed to prepare/enable clk, err=%d\n",
292				ret);
293			return ret;
294		}
295	}
296
297	return ret;
298}
299
300static void imx_disable_unprepare_clks(struct device *dev)
301{
302	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
303
304	if (data->need_three_clks) {
305		clk_disable_unprepare(data->clk_per);
306		clk_disable_unprepare(data->clk_ahb);
307		clk_disable_unprepare(data->clk_ipg);
308	} else {
309		clk_disable_unprepare(data->clk);
310	}
311}
312
313static int ci_hdrc_imx_notify_event(struct ci_hdrc *ci, unsigned int event)
314{
315	struct device *dev = ci->dev->parent;
316	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
317	int ret = 0;
318	struct imx_usbmisc_data *mdata = data->usbmisc_data;
319
320	switch (event) {
321	case CI_HDRC_IMX_HSIC_ACTIVE_EVENT:
322		if (data->pinctrl) {
323			ret = pinctrl_select_state(data->pinctrl,
324					data->pinctrl_hsic_active);
325			if (ret)
326				dev_err(dev,
327					"hsic_active select failed, err=%d\n",
328					ret);
329		}
330		break;
331	case CI_HDRC_IMX_HSIC_SUSPEND_EVENT:
332		ret = imx_usbmisc_hsic_set_connect(mdata);
333		if (ret)
334			dev_err(dev,
335				"hsic_set_connect failed, err=%d\n", ret);
336		break;
337	case CI_HDRC_CONTROLLER_VBUS_EVENT:
338		if (ci->vbus_active)
339			ret = imx_usbmisc_charger_detection(mdata, true);
340		else
341			ret = imx_usbmisc_charger_detection(mdata, false);
342		if (ci->usb_phy)
343			schedule_work(&ci->usb_phy->chg_work);
344		break;
345	case CI_HDRC_CONTROLLER_PULLUP_EVENT:
346		if (ci->role == CI_ROLE_GADGET &&
347		    ci->gadget.speed == USB_SPEED_HIGH)
348			imx_usbmisc_pullup(data->usbmisc_data,
349					   ci->gadget.connected);
350		break;
351	default:
352		break;
353	}
354
355	return ret;
356}
357
358static irqreturn_t ci_wakeup_irq_handler(int irq, void *data)
359{
360	struct ci_hdrc_imx_data *imx_data = data;
361
362	disable_irq_nosync(irq);
363	pm_runtime_resume(&imx_data->ci_pdev->dev);
364
365	return IRQ_HANDLED;
366}
367
368static void ci_hdrc_imx_disable_regulator(void *arg)
369{
370	struct ci_hdrc_imx_data *data = arg;
371
372	regulator_disable(data->hsic_pad_regulator);
373}
374
375static int ci_hdrc_imx_probe(struct platform_device *pdev)
376{
377	struct ci_hdrc_imx_data *data;
378	struct ci_hdrc_platform_data pdata = {
379		.name		= dev_name(&pdev->dev),
380		.capoffset	= DEF_CAPOFFSET,
381		.flags		= CI_HDRC_HAS_SHORT_PKT_LIMIT,
382		.notify_event	= ci_hdrc_imx_notify_event,
383	};
384	int ret;
385	const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
386	struct device_node *np = pdev->dev.of_node;
387	struct device *dev = &pdev->dev;
388
389	imx_platform_flag = of_device_get_match_data(&pdev->dev);
390
391	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
392	if (!data)
393		return -ENOMEM;
394
395	data->plat_data = imx_platform_flag;
396	pdata.flags |= imx_platform_flag->flags;
397	platform_set_drvdata(pdev, data);
398	data->usbmisc_data = usbmisc_get_init_data(dev);
399	if (IS_ERR(data->usbmisc_data))
400		return PTR_ERR(data->usbmisc_data);
401
402	if ((of_usb_get_phy_mode(dev->of_node) == USBPHY_INTERFACE_MODE_HSIC)
403		&& data->usbmisc_data) {
404		pdata.flags |= CI_HDRC_IMX_IS_HSIC;
405		data->usbmisc_data->hsic = 1;
406		data->pinctrl = devm_pinctrl_get(dev);
407		if (PTR_ERR(data->pinctrl) == -ENODEV)
408			data->pinctrl = NULL;
409		else if (IS_ERR(data->pinctrl)) {
410			ret = dev_err_probe(dev, PTR_ERR(data->pinctrl),
411					     "pinctrl get failed\n");
412			goto err_put;
413		}
414
415		data->hsic_pad_regulator =
416				devm_regulator_get_optional(dev, "hsic");
417		if (PTR_ERR(data->hsic_pad_regulator) == -ENODEV) {
418			/* no pad regulator is needed */
419			data->hsic_pad_regulator = NULL;
420		} else if (IS_ERR(data->hsic_pad_regulator)) {
421			ret = dev_err_probe(dev, PTR_ERR(data->hsic_pad_regulator),
422					     "Get HSIC pad regulator error\n");
423			goto err_put;
424		}
425
426		if (data->hsic_pad_regulator) {
427			ret = regulator_enable(data->hsic_pad_regulator);
428			if (ret) {
429				dev_err(dev,
430					"Failed to enable HSIC pad regulator\n");
431				goto err_put;
432			}
433			ret = devm_add_action_or_reset(dev,
434					ci_hdrc_imx_disable_regulator, data);
435			if (ret) {
436				dev_err(dev,
437					"Failed to add regulator devm action\n");
438				goto err_put;
439			}
440		}
441	}
442
443	/* HSIC pinctrl handling */
444	if (data->pinctrl) {
445		struct pinctrl_state *pinctrl_hsic_idle;
446
447		pinctrl_hsic_idle = pinctrl_lookup_state(data->pinctrl, "idle");
448		if (IS_ERR(pinctrl_hsic_idle)) {
449			dev_err(dev,
450				"pinctrl_hsic_idle lookup failed, err=%ld\n",
451					PTR_ERR(pinctrl_hsic_idle));
452			ret = PTR_ERR(pinctrl_hsic_idle);
453			goto err_put;
454		}
455
456		ret = pinctrl_select_state(data->pinctrl, pinctrl_hsic_idle);
457		if (ret) {
458			dev_err(dev, "hsic_idle select failed, err=%d\n", ret);
459			goto err_put;
460		}
461
462		data->pinctrl_hsic_active = pinctrl_lookup_state(data->pinctrl,
463								"active");
464		if (IS_ERR(data->pinctrl_hsic_active)) {
465			dev_err(dev,
466				"pinctrl_hsic_active lookup failed, err=%ld\n",
467					PTR_ERR(data->pinctrl_hsic_active));
468			ret = PTR_ERR(data->pinctrl_hsic_active);
469			goto err_put;
470		}
471	}
472
473	if (pdata.flags & CI_HDRC_PMQOS)
474		cpu_latency_qos_add_request(&data->pm_qos_req, 0);
475
476	ret = imx_get_clks(dev);
477	if (ret)
478		goto qos_remove_request;
479
480	ret = imx_prepare_enable_clks(dev);
481	if (ret)
482		goto qos_remove_request;
483
484	ret = clk_prepare_enable(data->clk_wakeup);
485	if (ret)
486		goto err_wakeup_clk;
487
488	data->phy = devm_usb_get_phy_by_phandle(dev, "fsl,usbphy", 0);
489	if (IS_ERR(data->phy)) {
490		ret = PTR_ERR(data->phy);
491		if (ret != -ENODEV) {
492			dev_err_probe(dev, ret, "Failed to parse fsl,usbphy\n");
493			goto err_clk;
494		}
495		data->phy = devm_usb_get_phy_by_phandle(dev, "phys", 0);
496		if (IS_ERR(data->phy)) {
497			ret = PTR_ERR(data->phy);
498			if (ret == -ENODEV) {
499				data->phy = NULL;
500			} else {
501				dev_err_probe(dev, ret, "Failed to parse phys\n");
502				goto err_clk;
503			}
504		}
505	}
506
507	pdata.usb_phy = data->phy;
508	if (data->usbmisc_data)
509		data->usbmisc_data->usb_phy = data->phy;
510
511	if ((of_device_is_compatible(np, "fsl,imx53-usb") ||
512	     of_device_is_compatible(np, "fsl,imx51-usb")) && pdata.usb_phy &&
513	    of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI) {
514		pdata.flags |= CI_HDRC_OVERRIDE_PHY_CONTROL;
515		data->override_phy_control = true;
516		ret = usb_phy_init(pdata.usb_phy);
517		if (ret) {
518			dev_err(dev, "Failed to init phy\n");
519			goto err_clk;
520		}
521	}
522
523	if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
524		data->supports_runtime_pm = true;
525
526	data->wakeup_irq = platform_get_irq_optional(pdev, 1);
527	if (data->wakeup_irq > 0) {
528		ret = devm_request_threaded_irq(dev, data->wakeup_irq,
529						NULL, ci_wakeup_irq_handler,
530						IRQF_ONESHOT | IRQF_NO_AUTOEN,
531						pdata.name, data);
532		if (ret)
533			goto err_clk;
534	}
535
536	ret = imx_usbmisc_init(data->usbmisc_data);
537	if (ret) {
538		dev_err(dev, "usbmisc init failed, ret=%d\n", ret);
539		goto phy_shutdown;
540	}
541
542	data->ci_pdev = ci_hdrc_add_device(dev,
543				pdev->resource, pdev->num_resources,
544				&pdata);
545	if (IS_ERR(data->ci_pdev)) {
546		ret = PTR_ERR(data->ci_pdev);
547		dev_err_probe(dev, ret, "ci_hdrc_add_device failed\n");
548		goto phy_shutdown;
549	}
550
551	if (data->usbmisc_data) {
552		if (!IS_ERR(pdata.id_extcon.edev) ||
553		    of_property_read_bool(np, "usb-role-switch"))
554			data->usbmisc_data->ext_id = 1;
555
556		if (!IS_ERR(pdata.vbus_extcon.edev) ||
557		    of_property_read_bool(np, "usb-role-switch"))
558			data->usbmisc_data->ext_vbus = 1;
559
560		/* usbmisc needs to know dr mode to choose wakeup setting */
561		data->usbmisc_data->available_role =
562			ci_hdrc_query_available_role(data->ci_pdev);
563	}
564
565	ret = imx_usbmisc_init_post(data->usbmisc_data);
566	if (ret) {
567		dev_err(dev, "usbmisc post failed, ret=%d\n", ret);
568		goto disable_device;
569	}
570
571	if (data->supports_runtime_pm) {
572		pm_runtime_set_active(dev);
573		pm_runtime_enable(dev);
574	}
575
576	device_set_wakeup_capable(dev, true);
577
578	return 0;
579
580disable_device:
581	ci_hdrc_remove_device(data->ci_pdev);
582phy_shutdown:
583	if (data->override_phy_control)
584		usb_phy_shutdown(data->phy);
585err_clk:
586	clk_disable_unprepare(data->clk_wakeup);
587err_wakeup_clk:
588	imx_disable_unprepare_clks(dev);
589qos_remove_request:
590	if (pdata.flags & CI_HDRC_PMQOS)
591		cpu_latency_qos_remove_request(&data->pm_qos_req);
592	data->ci_pdev = NULL;
593err_put:
594	if (data->usbmisc_data)
595		put_device(data->usbmisc_data->dev);
596	return ret;
597}
598
599static void ci_hdrc_imx_remove(struct platform_device *pdev)
600{
601	struct ci_hdrc_imx_data *data = platform_get_drvdata(pdev);
602
603	if (data->supports_runtime_pm) {
604		pm_runtime_get_sync(&pdev->dev);
605		pm_runtime_disable(&pdev->dev);
606		pm_runtime_put_noidle(&pdev->dev);
607	}
608	if (data->ci_pdev)
609		ci_hdrc_remove_device(data->ci_pdev);
610	if (data->override_phy_control)
611		usb_phy_shutdown(data->phy);
612	if (data->ci_pdev) {
613		imx_disable_unprepare_clks(&pdev->dev);
614		clk_disable_unprepare(data->clk_wakeup);
615		if (data->plat_data->flags & CI_HDRC_PMQOS)
616			cpu_latency_qos_remove_request(&data->pm_qos_req);
617	}
618	if (data->usbmisc_data)
619		put_device(data->usbmisc_data->dev);
620}
621
622static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
623{
624	ci_hdrc_imx_remove(pdev);
625}
626
627static int imx_controller_suspend(struct device *dev,
628						 pm_message_t msg)
629{
630	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
631	int ret = 0;
632
633	dev_dbg(dev, "at %s\n", __func__);
634
635	ret = imx_usbmisc_suspend(data->usbmisc_data,
636				  PMSG_IS_AUTO(msg) || device_may_wakeup(dev));
637	if (ret) {
638		dev_err(dev,
639			"usbmisc suspend failed, ret=%d\n", ret);
640		return ret;
641	}
642
643	imx_disable_unprepare_clks(dev);
644
645	if (data->wakeup_irq > 0)
646		enable_irq(data->wakeup_irq);
647
648	if (data->plat_data->flags & CI_HDRC_PMQOS)
649		cpu_latency_qos_remove_request(&data->pm_qos_req);
650
651	data->in_lpm = true;
652
653	return 0;
654}
655
656static int imx_controller_resume(struct device *dev,
657						pm_message_t msg)
658{
659	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
660	int ret = 0;
661
662	dev_dbg(dev, "at %s\n", __func__);
663
664	if (!data->in_lpm) {
665		WARN_ON(1);
666		return 0;
667	}
668
669	if (data->plat_data->flags & CI_HDRC_PMQOS)
670		cpu_latency_qos_add_request(&data->pm_qos_req, 0);
671
672	if (data->wakeup_irq > 0 &&
673	    !irqd_irq_disabled(irq_get_irq_data(data->wakeup_irq)))
674		disable_irq_nosync(data->wakeup_irq);
675
676	ret = imx_prepare_enable_clks(dev);
677	if (ret)
678		return ret;
679
680	data->in_lpm = false;
681
682	ret = imx_usbmisc_resume(data->usbmisc_data,
683				 PMSG_IS_AUTO(msg) || device_may_wakeup(dev));
684	if (ret) {
685		dev_err(dev, "usbmisc resume failed, ret=%d\n", ret);
686		goto clk_disable;
687	}
688
689	return 0;
690
691clk_disable:
692	imx_disable_unprepare_clks(dev);
693	return ret;
694}
695
696static int ci_hdrc_imx_suspend(struct device *dev)
697{
698	int ret;
699
700	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
701
702	if (data->in_lpm)
703		/* The core's suspend doesn't run */
704		return 0;
705
706	ret = imx_controller_suspend(dev, PMSG_SUSPEND);
707	if (ret)
708		return ret;
709
710	pinctrl_pm_select_sleep_state(dev);
711
712	if (data->wakeup_irq > 0 && device_may_wakeup(dev)) {
713		enable_irq_wake(data->wakeup_irq);
714
715		if (data->plat_data->flags & CI_HDRC_OUT_BAND_WAKEUP)
716			device_set_out_band_wakeup(dev);
717	}
718
719	return ret;
720}
721
722static int ci_hdrc_imx_resume(struct device *dev)
723{
724	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
725	int ret;
726
727	if (data->wakeup_irq > 0 && device_may_wakeup(dev))
728		disable_irq_wake(data->wakeup_irq);
729
730	pinctrl_pm_select_default_state(dev);
731	ret = imx_controller_resume(dev, PMSG_RESUME);
732	if (!ret && data->supports_runtime_pm) {
733		pm_runtime_disable(dev);
734		pm_runtime_set_active(dev);
735		pm_runtime_enable(dev);
736	}
737
738	return ret;
739}
740
741static int ci_hdrc_imx_runtime_suspend(struct device *dev)
742{
743	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
744
745	if (data->in_lpm) {
746		WARN_ON(1);
747		return 0;
748	}
749
750	return imx_controller_suspend(dev, PMSG_AUTO_SUSPEND);
751}
752
753static int ci_hdrc_imx_runtime_resume(struct device *dev)
754{
755	return imx_controller_resume(dev, PMSG_AUTO_RESUME);
756}
757
758static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
759	SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
760	RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend, ci_hdrc_imx_runtime_resume, NULL)
761};
762static struct platform_driver ci_hdrc_imx_driver = {
763	.probe = ci_hdrc_imx_probe,
764	.remove = ci_hdrc_imx_remove,
765	.shutdown = ci_hdrc_imx_shutdown,
766	.driver = {
767		.name = "imx_usb",
768		.of_match_table = ci_hdrc_imx_dt_ids,
769		.pm = pm_ptr(&ci_hdrc_imx_pm_ops),
770	 },
771};
772
773module_platform_driver(ci_hdrc_imx_driver);
774
775MODULE_ALIAS("platform:imx-usb");
776MODULE_LICENSE("GPL");
777MODULE_DESCRIPTION("CI HDRC i.MX USB binding");
778MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
779MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
~/ Read-only file preview.