1 /*
2  * Copyright 2012 Freescale Semiconductor, Inc.
3  * Copyright (C) 2012 Marek Vasut <marex@denx.de>
4  * on behalf of DENX Software Engineering GmbH
5  *
6  * The code contained herein is licensed under the GNU General Public
7  * License. You may obtain a copy of the GNU General Public License
8  * Version 2 or later at the following locations:
9  *
10  * http://www.opensource.org/licenses/gpl-license.html
11  * http://www.gnu.org/copyleft/gpl.html
12  */
13 
14 #include <linux/module.h>
15 #include <linux/of_platform.h>
16 #include <linux/of_gpio.h>
17 #include <linux/platform_device.h>
18 #include <linux/pm_runtime.h>
19 #include <linux/dma-mapping.h>
20 #include <linux/usb/chipidea.h>
21 #include <linux/usb/of.h>
22 #include <linux/clk.h>
23 
24 #include "ci.h"
25 #include "ci_hdrc_imx.h"
26 
27 struct ci_hdrc_imx_platform_flag {
28 	unsigned int flags;
29 	bool runtime_pm;
30 };
31 
32 static const struct ci_hdrc_imx_platform_flag imx23_usb_data = {
33 	.flags = CI_HDRC_TURN_VBUS_EARLY_ON |
34 		CI_HDRC_DISABLE_STREAMING,
35 };
36 
37 static const struct ci_hdrc_imx_platform_flag imx27_usb_data = {
38 		CI_HDRC_DISABLE_STREAMING,
39 };
40 
41 static const struct ci_hdrc_imx_platform_flag imx28_usb_data = {
42 	.flags = CI_HDRC_IMX28_WRITE_FIX |
43 		CI_HDRC_TURN_VBUS_EARLY_ON |
44 		CI_HDRC_DISABLE_STREAMING,
45 };
46 
47 static const struct ci_hdrc_imx_platform_flag imx6q_usb_data = {
48 	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
49 		CI_HDRC_TURN_VBUS_EARLY_ON |
50 		CI_HDRC_DISABLE_STREAMING,
51 };
52 
53 static const struct ci_hdrc_imx_platform_flag imx6sl_usb_data = {
54 	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
55 		CI_HDRC_TURN_VBUS_EARLY_ON |
56 		CI_HDRC_DISABLE_HOST_STREAMING,
57 };
58 
59 static const struct ci_hdrc_imx_platform_flag imx6sx_usb_data = {
60 	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
61 		CI_HDRC_TURN_VBUS_EARLY_ON |
62 		CI_HDRC_DISABLE_HOST_STREAMING,
63 };
64 
65 static const struct ci_hdrc_imx_platform_flag imx6ul_usb_data = {
66 	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM |
67 		CI_HDRC_TURN_VBUS_EARLY_ON,
68 };
69 
70 static const struct ci_hdrc_imx_platform_flag imx7d_usb_data = {
71 	.flags = CI_HDRC_SUPPORTS_RUNTIME_PM,
72 };
73 
74 static const struct of_device_id ci_hdrc_imx_dt_ids[] = {
75 	{ .compatible = "fsl,imx23-usb", .data = &imx23_usb_data},
76 	{ .compatible = "fsl,imx28-usb", .data = &imx28_usb_data},
77 	{ .compatible = "fsl,imx27-usb", .data = &imx27_usb_data},
78 	{ .compatible = "fsl,imx6q-usb", .data = &imx6q_usb_data},
79 	{ .compatible = "fsl,imx6sl-usb", .data = &imx6sl_usb_data},
80 	{ .compatible = "fsl,imx6sx-usb", .data = &imx6sx_usb_data},
81 	{ .compatible = "fsl,imx6ul-usb", .data = &imx6ul_usb_data},
82 	{ .compatible = "fsl,imx7d-usb", .data = &imx7d_usb_data},
83 	{ /* sentinel */ }
84 };
85 MODULE_DEVICE_TABLE(of, ci_hdrc_imx_dt_ids);
86 
87 struct ci_hdrc_imx_data {
88 	struct usb_phy *phy;
89 	struct platform_device *ci_pdev;
90 	struct clk *clk;
91 	struct imx_usbmisc_data *usbmisc_data;
92 	bool supports_runtime_pm;
93 	bool in_lpm;
94 	/* SoC before i.mx6 (except imx23/imx28) needs three clks */
95 	bool need_three_clks;
96 	struct clk *clk_ipg;
97 	struct clk *clk_ahb;
98 	struct clk *clk_per;
99 	/* --------------------------------- */
100 };
101 
102 /* Common functions shared by usbmisc drivers */
103 
104 static struct imx_usbmisc_data *usbmisc_get_init_data(struct device *dev)
105 {
106 	struct platform_device *misc_pdev;
107 	struct device_node *np = dev->of_node;
108 	struct of_phandle_args args;
109 	struct imx_usbmisc_data *data;
110 	int ret;
111 
112 	/*
113 	 * In case the fsl,usbmisc property is not present this device doesn't
114 	 * need usbmisc. Return NULL (which is no error here)
115 	 */
116 	if (!of_get_property(np, "fsl,usbmisc", NULL))
117 		return NULL;
118 
119 	data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
120 	if (!data)
121 		return ERR_PTR(-ENOMEM);
122 
123 	ret = of_parse_phandle_with_args(np, "fsl,usbmisc", "#index-cells",
124 					0, &args);
125 	if (ret) {
126 		dev_err(dev, "Failed to parse property fsl,usbmisc, errno %d\n",
127 			ret);
128 		return ERR_PTR(ret);
129 	}
130 
131 	data->index = args.args[0];
132 
133 	misc_pdev = of_find_device_by_node(args.np);
134 	of_node_put(args.np);
135 
136 	if (!misc_pdev || !platform_get_drvdata(misc_pdev))
137 		return ERR_PTR(-EPROBE_DEFER);
138 
139 	data->dev = &misc_pdev->dev;
140 
141 	if (of_find_property(np, "disable-over-current", NULL))
142 		data->disable_oc = 1;
143 
144 	if (of_find_property(np, "over-current-active-high", NULL))
145 		data->oc_polarity = 1;
146 
147 	if (of_find_property(np, "external-vbus-divider", NULL))
148 		data->evdo = 1;
149 
150 	if (of_usb_get_phy_mode(np) == USBPHY_INTERFACE_MODE_ULPI)
151 		data->ulpi = 1;
152 
153 	return data;
154 }
155 
156 /* End of common functions shared by usbmisc drivers*/
157 static int imx_get_clks(struct device *dev)
158 {
159 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
160 	int ret = 0;
161 
162 	data->clk_ipg = devm_clk_get(dev, "ipg");
163 	if (IS_ERR(data->clk_ipg)) {
164 		/* If the platform only needs one clocks */
165 		data->clk = devm_clk_get(dev, NULL);
166 		if (IS_ERR(data->clk)) {
167 			ret = PTR_ERR(data->clk);
168 			dev_err(dev,
169 				"Failed to get clks, err=%ld,%ld\n",
170 				PTR_ERR(data->clk), PTR_ERR(data->clk_ipg));
171 			return ret;
172 		}
173 		return ret;
174 	}
175 
176 	data->clk_ahb = devm_clk_get(dev, "ahb");
177 	if (IS_ERR(data->clk_ahb)) {
178 		ret = PTR_ERR(data->clk_ahb);
179 		dev_err(dev,
180 			"Failed to get ahb clock, err=%d\n", ret);
181 		return ret;
182 	}
183 
184 	data->clk_per = devm_clk_get(dev, "per");
185 	if (IS_ERR(data->clk_per)) {
186 		ret = PTR_ERR(data->clk_per);
187 		dev_err(dev,
188 			"Failed to get per clock, err=%d\n", ret);
189 		return ret;
190 	}
191 
192 	data->need_three_clks = true;
193 	return ret;
194 }
195 
196 static int imx_prepare_enable_clks(struct device *dev)
197 {
198 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
199 	int ret = 0;
200 
201 	if (data->need_three_clks) {
202 		ret = clk_prepare_enable(data->clk_ipg);
203 		if (ret) {
204 			dev_err(dev,
205 				"Failed to prepare/enable ipg clk, err=%d\n",
206 				ret);
207 			return ret;
208 		}
209 
210 		ret = clk_prepare_enable(data->clk_ahb);
211 		if (ret) {
212 			dev_err(dev,
213 				"Failed to prepare/enable ahb clk, err=%d\n",
214 				ret);
215 			clk_disable_unprepare(data->clk_ipg);
216 			return ret;
217 		}
218 
219 		ret = clk_prepare_enable(data->clk_per);
220 		if (ret) {
221 			dev_err(dev,
222 				"Failed to prepare/enable per clk, err=%d\n",
223 				ret);
224 			clk_disable_unprepare(data->clk_ahb);
225 			clk_disable_unprepare(data->clk_ipg);
226 			return ret;
227 		}
228 	} else {
229 		ret = clk_prepare_enable(data->clk);
230 		if (ret) {
231 			dev_err(dev,
232 				"Failed to prepare/enable clk, err=%d\n",
233 				ret);
234 			return ret;
235 		}
236 	}
237 
238 	return ret;
239 }
240 
241 static void imx_disable_unprepare_clks(struct device *dev)
242 {
243 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
244 
245 	if (data->need_three_clks) {
246 		clk_disable_unprepare(data->clk_per);
247 		clk_disable_unprepare(data->clk_ahb);
248 		clk_disable_unprepare(data->clk_ipg);
249 	} else {
250 		clk_disable_unprepare(data->clk);
251 	}
252 }
253 
254 static int ci_hdrc_imx_probe(struct platform_device *pdev)
255 {
256 	struct ci_hdrc_imx_data *data;
257 	struct ci_hdrc_platform_data pdata = {
258 		.name		= dev_name(&pdev->dev),
259 		.capoffset	= DEF_CAPOFFSET,
260 	};
261 	int ret;
262 	const struct of_device_id *of_id;
263 	const struct ci_hdrc_imx_platform_flag *imx_platform_flag;
264 
265 	of_id = of_match_device(ci_hdrc_imx_dt_ids, &pdev->dev);
266 	if (!of_id)
267 		return -ENODEV;
268 
269 	imx_platform_flag = of_id->data;
270 
271 	data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
272 	if (!data)
273 		return -ENOMEM;
274 
275 	platform_set_drvdata(pdev, data);
276 	data->usbmisc_data = usbmisc_get_init_data(&pdev->dev);
277 	if (IS_ERR(data->usbmisc_data))
278 		return PTR_ERR(data->usbmisc_data);
279 
280 	ret = imx_get_clks(&pdev->dev);
281 	if (ret)
282 		return ret;
283 
284 	ret = imx_prepare_enable_clks(&pdev->dev);
285 	if (ret)
286 		return ret;
287 
288 	data->phy = devm_usb_get_phy_by_phandle(&pdev->dev, "fsl,usbphy", 0);
289 	if (IS_ERR(data->phy)) {
290 		ret = PTR_ERR(data->phy);
291 		/* Return -EINVAL if no usbphy is available */
292 		if (ret == -ENODEV)
293 			ret = -EINVAL;
294 		goto err_clk;
295 	}
296 
297 	pdata.usb_phy = data->phy;
298 	pdata.flags |= imx_platform_flag->flags;
299 	if (pdata.flags & CI_HDRC_SUPPORTS_RUNTIME_PM)
300 		data->supports_runtime_pm = true;
301 
302 	ret = imx_usbmisc_init(data->usbmisc_data);
303 	if (ret) {
304 		dev_err(&pdev->dev, "usbmisc init failed, ret=%d\n", ret);
305 		goto err_clk;
306 	}
307 
308 	data->ci_pdev = ci_hdrc_add_device(&pdev->dev,
309 				pdev->resource, pdev->num_resources,
310 				&pdata);
311 	if (IS_ERR(data->ci_pdev)) {
312 		ret = PTR_ERR(data->ci_pdev);
313 		if (ret != -EPROBE_DEFER)
314 			dev_err(&pdev->dev,
315 				"ci_hdrc_add_device failed, err=%d\n", ret);
316 		goto err_clk;
317 	}
318 
319 	ret = imx_usbmisc_init_post(data->usbmisc_data);
320 	if (ret) {
321 		dev_err(&pdev->dev, "usbmisc post failed, ret=%d\n", ret);
322 		goto disable_device;
323 	}
324 
325 	if (data->supports_runtime_pm) {
326 		pm_runtime_set_active(&pdev->dev);
327 		pm_runtime_enable(&pdev->dev);
328 	}
329 
330 	device_set_wakeup_capable(&pdev->dev, true);
331 
332 	return 0;
333 
334 disable_device:
335 	ci_hdrc_remove_device(data->ci_pdev);
336 err_clk:
337 	imx_disable_unprepare_clks(&pdev->dev);
338 	return ret;
339 }
340 
341 static int ci_hdrc_imx_remove(struct platform_device *pdev)
342 {
343 	struct ci_hdrc_imx_data *data = platform_get_drvdata(pdev);
344 
345 	if (data->supports_runtime_pm) {
346 		pm_runtime_get_sync(&pdev->dev);
347 		pm_runtime_disable(&pdev->dev);
348 		pm_runtime_put_noidle(&pdev->dev);
349 	}
350 	ci_hdrc_remove_device(data->ci_pdev);
351 	imx_disable_unprepare_clks(&pdev->dev);
352 
353 	return 0;
354 }
355 
356 static void ci_hdrc_imx_shutdown(struct platform_device *pdev)
357 {
358 	ci_hdrc_imx_remove(pdev);
359 }
360 
361 #ifdef CONFIG_PM
362 static int imx_controller_suspend(struct device *dev)
363 {
364 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
365 
366 	dev_dbg(dev, "at %s\n", __func__);
367 
368 	imx_disable_unprepare_clks(dev);
369 	data->in_lpm = true;
370 
371 	return 0;
372 }
373 
374 static int imx_controller_resume(struct device *dev)
375 {
376 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
377 	int ret = 0;
378 
379 	dev_dbg(dev, "at %s\n", __func__);
380 
381 	if (!data->in_lpm) {
382 		WARN_ON(1);
383 		return 0;
384 	}
385 
386 	ret = imx_prepare_enable_clks(dev);
387 	if (ret)
388 		return ret;
389 
390 	data->in_lpm = false;
391 
392 	ret = imx_usbmisc_set_wakeup(data->usbmisc_data, false);
393 	if (ret) {
394 		dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
395 		goto clk_disable;
396 	}
397 
398 	return 0;
399 
400 clk_disable:
401 	imx_disable_unprepare_clks(dev);
402 	return ret;
403 }
404 
405 #ifdef CONFIG_PM_SLEEP
406 static int ci_hdrc_imx_suspend(struct device *dev)
407 {
408 	int ret;
409 
410 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
411 
412 	if (data->in_lpm)
413 		/* The core's suspend doesn't run */
414 		return 0;
415 
416 	if (device_may_wakeup(dev)) {
417 		ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
418 		if (ret) {
419 			dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n",
420 					ret);
421 			return ret;
422 		}
423 	}
424 
425 	return imx_controller_suspend(dev);
426 }
427 
428 static int ci_hdrc_imx_resume(struct device *dev)
429 {
430 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
431 	int ret;
432 
433 	ret = imx_controller_resume(dev);
434 	if (!ret && data->supports_runtime_pm) {
435 		pm_runtime_disable(dev);
436 		pm_runtime_set_active(dev);
437 		pm_runtime_enable(dev);
438 	}
439 
440 	return ret;
441 }
442 #endif /* CONFIG_PM_SLEEP */
443 
444 static int ci_hdrc_imx_runtime_suspend(struct device *dev)
445 {
446 	struct ci_hdrc_imx_data *data = dev_get_drvdata(dev);
447 	int ret;
448 
449 	if (data->in_lpm) {
450 		WARN_ON(1);
451 		return 0;
452 	}
453 
454 	ret = imx_usbmisc_set_wakeup(data->usbmisc_data, true);
455 	if (ret) {
456 		dev_err(dev, "usbmisc set_wakeup failed, ret=%d\n", ret);
457 		return ret;
458 	}
459 
460 	return imx_controller_suspend(dev);
461 }
462 
463 static int ci_hdrc_imx_runtime_resume(struct device *dev)
464 {
465 	return imx_controller_resume(dev);
466 }
467 
468 #endif /* CONFIG_PM */
469 
470 static const struct dev_pm_ops ci_hdrc_imx_pm_ops = {
471 	SET_SYSTEM_SLEEP_PM_OPS(ci_hdrc_imx_suspend, ci_hdrc_imx_resume)
472 	SET_RUNTIME_PM_OPS(ci_hdrc_imx_runtime_suspend,
473 			ci_hdrc_imx_runtime_resume, NULL)
474 };
475 static struct platform_driver ci_hdrc_imx_driver = {
476 	.probe = ci_hdrc_imx_probe,
477 	.remove = ci_hdrc_imx_remove,
478 	.shutdown = ci_hdrc_imx_shutdown,
479 	.driver = {
480 		.name = "imx_usb",
481 		.of_match_table = ci_hdrc_imx_dt_ids,
482 		.pm = &ci_hdrc_imx_pm_ops,
483 	 },
484 };
485 
486 module_platform_driver(ci_hdrc_imx_driver);
487 
488 MODULE_ALIAS("platform:imx-usb");
489 MODULE_LICENSE("GPL v2");
490 MODULE_DESCRIPTION("CI HDRC i.MX USB binding");
491 MODULE_AUTHOR("Marek Vasut <marex@denx.de>");
492 MODULE_AUTHOR("Richard Zhao <richard.zhao@freescale.com>");
493